[
  {
    "path": ".gitignore",
    "content": ".DS_STORE\n\n.env\nnotes/email-activation.py\nsrc/ecommerce/aws/ignore2.py\n\n# Virtualenv related\nbin/\ninclude/\npip-selfcheck.json\n\n# Django related \n# src/<yourproject>/settings/local.py\n# static-cdn/  # any collected static files \n\n\n# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n.hypothesis/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# pyenv\n.python-version\n\n# celery beat schedule file\ncelerybeat-schedule\n\n# SageMath parsed files\n*.sage.py\n\n# Environments\n.env\n.venv\nenv/\nvenv/\nENV/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\n\n\n"
  },
  {
    "path": "README.md",
    "content": "# eCommerce\n\n[![eCommerce Logo](https://cfe2-static.s3-us-west-2.amazonaws.com/media/courses/ecommerce/images/ecommerce_coding_for_entrepreneurs.jpg)\n](https://www.codingforentrepreneurs.com/courses/ecommerce/)\n\nThis course will teach you step-by-step to build a eCommerce site from scratch. We'll be using open-source software to create each aspect of a fully functioning eCommerce business.\n\nFull Course is here: [https://www.joincfe.com/courses/ecommerce/](https://www.joincfe.com/courses/ecommerce/)\n\nBelow you'll find the related lecture code to any given section and lesson. Enjoy!\n\n\n# Code\n\n### Section - Hello World\n\n[Intial Commit](../../tree/0927b316e9cdd8b0db01263b6b429e698d38d57a/)\n\n\n### Section - Products Component\n\n[1 - Your first app Module](../../tree/ed8ceb52830b762d50bbf44f680255168c6f5530/)\n\n[2 - Understanding CRUD](../../tree/aaa75b9c3ffba674e3661175922b99149fd4bdd9/)\n\n[3 - Product Model](../../tree/a80ded7e6ed9a87da9a8029e4e6fe50c18fd4b79/)\n\n[4 - Django Admin](../../tree/311291431e55a783532ff3cd9319e22d77ff92c0/)\n\n[5 - List View](../../tree/ab27c4cc095ae00d51b71545cf6118813c12828f/)\n\n[6 - Detail View](../../tree/b7343749415fb9a6a6a629859684f13a0afbf787/)\n\n[7 - ImageField & FileField](../../tree/08a2426622b6536de6ae16637cc9489eeda5e484/)\n\n[8 - Understanding Lookups](../../tree/6a1116a90d9c24ca4366a3764b20de61a83f52ac/)\n\n[9 - Custom Model Managers](../../tree/f146e4775cb274176897f8e06d842150599aa3c5/)\n\n[10 - Featured & Custom QuerySets](../../tree/8f7cf0ea87b89672f1ca745a251de32598ff5754/)\n\n[11 - SlugField & Signals](../../tree/dc523d5e9aa18a730edd9819c6202fd3ecc20de7/)\n\n[12 - Products URLs](../../tree/959a578bd51964af2a637e2d75423568a8d7972b/)\n\n\n\n### Section: Templates\n\n[1 Base Template](../../tree/b34bc1692301719be722bb691c1d67df4e98b455/)\n\n[2 - Include Tag](../../tree/12fd4dd9fcd8616b7b71d8c93a60013aa01350d9/)\n\n[3 Pass Arguments with Include](../../tree/f68b6c15804033937d823f6a707df363901fd6a1/)\n\n[4 - Reusable List View Snippets](../../tree/e59e0938d032e68431c60718f27bfa2abbbd36b0/)\n\n[5 - Reverse for URLs](../../tree/4add77ea1751952f79aaf358bcfecac366ad6ac2/)\n\n[6 - Navbar](../../tree/fc97ee8fd094a47aeb47ad7b25cf2d5a04c78fe8/)\n\n[7 - Template Filters](../../tree/670ddd0ec4cec879a424fe05ac594e863b7dea53/)\n\n[8 - ForLoop Counter & Cycle](../../tree/e47bec09440f7938246c4b9210bd3f131d290dd0/)\n\n\n\n### Section: Bootstrap\n\n1 - Adding Bootstrap (no code)\n\n2 - Container vs Container-Fluid (no code)\n\n[3 - Rows And Columns](../../tree/d0e38edee652c5787dc7bf12e2ec2909fa3121f8/)\n\n[4 - Column Sizing](../../tree/b06f0a6661ac37d71be3fe38580bb561f71d2e42/)\n\n[6 - Desinging for Different Browser Sizes with Breakpoints](../../tree/225b29ccbff4aa3098e58d34a434dda495f7fb53/)\n\n[7 - Spacing with Margin & Padding](../../tree/e2eb9bc70e33b4870e87554a81bdee9179f0136d/)\n\n[8 - Navbar](../../tree/696987b4e9144296f681fb229e3420219f9a1026/)\n\n[10 - Integrate to Django](../../tree/6aa47a5627c5f57b3fca3cb52738c96609cc3746/)\n\n\n\n### Section: Search Component\n\n[1 - A Basic Search View](../../tree/28aa4043b5ad94a3095ddf3b77fd81a429803ff4/)\n\n[2 - Display the Query to the User](../../tree/e499a814c144497145c689be5626e175b2cd9a6d/)\n\n[3 - Creating the Search Form](../../tree/147efe3fae7b35702050b3f27907c13379a3f85d/)\n\n[4 - Better Lookups with Q](../../tree/54e65447fd0cd9b269c76ac1c9739af9cb1cd7ce/)\n\n[5 - Tag Component](../../tree/883d856330fe86d0ad697fa9cfebf19454b163be/)\n\n[6 - Shell Commands for a Brief Intro to Foreign Keys](../../tree/a85117d052ceaa054f1b025613bbbc46695ea0c0/)\n\n[7 - Search by Related Model](../../tree/908e3e07bc2e3ec5f157f6a06f59ad01395b4a2d/)\n\n\n\n\n### Section: Cart Component\n\n[1 - Cart App](../../tree/ab6ba98698080e5290f0c72e94edc6ebea229a4e/)\n\n[2 - Django Sessions](../../tree/4b2544743e5b3c650231cf10f8f4ba3f85e10382/)\n\n[3 - Cart Model](../../tree/0441dc0e50937eaec64bafa4f9258de70db7efc9/)\n\n[4 - Create A Cart in the View](../../tree/35e8bf075b51d32a7c0fcc1c191700736d64edfc/)\n\n[5 - Cart Model Manager](../../tree/3f9592bd3209ae09d5aa839c87356d7c1c6bc1bd/)\n\n[5 - Cart Model Manager Part 2](../../tree/20368456287ce253d2b51c7f4d2101f52ceb4d35/)\n\n[7 - M2M Changed Signal to Calculate Cart Total](../../tree/c64ba909c1b6af3b5b0502412eef20857cdaa25a/)\n\n[8 - Cart Update View](../../tree/864ef942a2331669d0a1c2385431688888916b22/)\n\n[9 - Add to Cart Form](../../tree/d5cced3c944f39164a36b4ef122ba2369006fc92/)\n\n[10 - Display Cart](../../tree/248c772322547fc7b331fa042627285f67a233a1/)\n\n[11 - Remove Items from the Cart](../../tree/3d7c0fc7fe264eded57ce3244e3ee86d1550a966/)\n\n[12 - Cart Icon & FontAwesome](../../tree/691d5ae69e2b5a8f569be0ede3efd5c9fc7897d3/)\n\n\n\n### Section: Checkout Process\n\n[1 - The Roadmap for the Checkout Process](../../tree/14bb24d788f96cb5e8593084428de5dcc0bc43b7/)\n\n[2 - The Order Component](../../tree/e3edacb39b6b5df4ee0b98297df42909784f86c3/)\n\n[3 - Generate the Order ID](../../tree/cfcc598dd86ce7ba795641f7520b58cf21c2e4de/)\n\n[4 - Calculate the Order Total](../../tree/00a2b87d1bfc671d62514679881cbccd62bc2494/)\n\n[5 - Checkout View](../../tree/40e7c81aa1dc18b1878c6097e486624b5163bc83/)\n\n[6 - Math with Decimals and Floats in Python](../../tree/3baac51bf5bf9fe1d1432d140fbdb5de0e3a6752/)\n\n[7 - Upgrading Auth to Prep for Checkout](../../tree/182d7a5da10a5799ca7c053849f39cba426a84eb/)\n\n[8 - Billing Profile Model\"](../../tree/3dd97d4cee6c4540410fda0006768bff523e9970/)\n\n[9 - Billing Profile in the Checkout View](../../tree/c0ff6dfdc8991c9a54889a616c327420f1d12939/)\n\n[10 - Guest Checkout Profile](../../tree/e4114e17297c3c437f1cd7e50d7f01e716d1af09/)\n\n[11 - Associate Billing Profile to Order](../../tree/b920068b6d80245344ab424f1e1b33a4e54888e4/)\n\n[12 - Order Manager](../../tree/a0e30cbe85971622c10e8d1bbf930dbaa78695d9/)\n\n[13 - Billing Profile Manager](../../tree/91bf2029c4da79168513dd12fe8ef2f6ac7e18e6/)\n\n[14 - Addresses App](../../tree/159d284645e99feedf94ce5b3693b4a28994c6d8/)\n\n[16 - Associate Addresses to Order](../../tree/3cee508cfe5228a45a919066bbf3bc14c23e824b/)\n\n[17 - Finalize Checkout](../../tree/f38442a8b770d0cea454280fd997a60b712d57ea/)\n\n[18 - Reuse Addresses for Checkout](../../tree/0ba33ba8e29482ed86ea2fe4a956bf7be01e05dd/)\n\n[19 - Checkout Success](../../tree/648e281ed5a8fff4fdf3d9959e0d32ec232a6624/)\n\n\n### Section: Fast Track to Jquery\n[1 - Getting Started](../../tree/bb9938c039d604ab39696ec166210f72edc2521e/)\n\n[2 - A Basic Selector](../../tree/5640cc849c8db492e1d98cc6070b7efb9c6c201c/)\n\n[3 - Selectors Part 2](../../tree/4cd3edb60b092c996de5a5812e007568ac898979/)\n\n[4 - Content Overflow Part 1](../../tree/bcbfb9973673f2d22e1c1af094d7e722237a2652/)\n\n[5 - Data Types, Iteration and Conditionals](../../tree/ec9b8d3277cea37b225ce81e68d00bd46745f5d7/)\n\n[6 - Content Overflow Part 2](../../tree/d4b8fedec4d61d3d6c1f442505c76b43ee613a70/)\n\n[7 - Click Events](../../tree/13c278c521032f6266e411bef97ad996b501379b/)\n\n[8 - Handling form data in jQuery](../../tree/69201626395880675420d187f55744f6a3c267ca/)\n\n\n\n### Section: Products & Async\n\n1 - Sync vs Async (no code)\n\n[2 - Ajax-ify a Form](../../tree/1d4d7ca41f515f4c12fed183023fde22463d8058/)\n\n[3 - Handle Ajax in Django with JsonResponse](../../tree/d6acdc28e52f47257afb4c4b3dc6e5f398f39e43/)\n\n[4 - Cart Item Count](../../tree/9455685b79a7ba829799d6dc700dce71c930c5d3/)\n\n[5 - Refresh Cart Ajax](../../tree/dba7c5401106c658a4a29729a1d5fb5efa596c2f/)\n\n[6 & 7 - Refresh Cart Ajax Part 2 & 3](../../tree/7f38a87f80d0c9a32e7e10149af1b19e8aa3d362/)\n\n[8 - Finalize Cart Updating with Ajax](../../tree/c16e30dbd9af01fddef5614f3857de4a7fcace3b/)\n\n[8 - Finalize Cart Updating with Ajax](../../tree/2072edc9f0451a8d9c88e0c6c9394310234331a8/)\n\n[9 - Auto Search](../../tree/c433c4a06ab3d0d199e4a46b390cc98a0328bad1/)\n\n[10 - Display Errors with jQuery Confirm](../../tree/ab040383aeed92a5ab457d25320fc1dddf72bc5d/)\n\n[11 - Ajaxify the Contact Form Part 1 & 2](../../tree/cc35747ceba808fd57350eaf59e51f95a7b091c4/)\n\n[13 - Custom eCommerce JS](../../tree/3431064fde1394e586076b23ba76827e03d626ce/)\n\n[14 - Ajax CSRF Security for Django](../../tree/82111856925f0d9a83eb08c0e937a95ca788d641/)\n\n\n## Add Ons\n\n### Custom Django User Model\n\n1 - Before we get started (no code)\n\n[2 - Create the Abstract Base User](../../tree/c698e75c82b6145546c93f8d32fec616dfaf1cac/)\n\n[3 - Create the User Model Manager](../../tree/968ec0525e27c3d95f9fc033833264437f90a47b/)\n\n4 - Change Auth User Model to our Custom Model (no code)\n\n[5 - Reload the Database with Fixtures](../../tree/96261517bc1e4c7b2603232569de479ae4c44a9d/)\n\n[6 - Forms & Admin for our Custom User](../../tree/464ff60dd57e8babf0096670f6bb5c62bdaa2e2c/)\n\n[7 - Add a Required Field to the User Model](../../tree/c12eebf5e8c5961b18f65f8741880f40f6cfc99b/)\n\n[8 - Update Login & Register Forms](../../tree/aefcaac8eb1f4f0d7e6f68dde46eb9f82f7e5ff7/)\n\n[9 - Login & Register Views](../../tree/3cccc2c44b9d81fcc4db4ed9bae77a8e23cf263e/)\n\n\n\n### Custom Analytics\n\n1 - Getting Started (No Code)\n\n[2 - Craft the Object Viewed Model](../../tree/dcea55fce60dcb56dc933fc0485a95a5a44b0c9d/)\n\n[3 - Get Client IP Address](../../tree/007dd5190b872ef32ab8164efd7631f7bef3a409/)\n\n[4 - A Custom Signal](../../tree/540a9e1f29e896c3145ead7231d76960031bb2c9/)\n\n[5 - Object Viewed Mixin](../../tree/73bfc3e04beee52b9ad6cd503d3b7c8d8ebeb71e/)\n\n[6 - Handle the Object Viewed Signal](../../tree/73bfc3e04beee52b9ad6cd503d3b7c8d8ebeb71e/)\n\n[7 - Handling and Ending User Sessions](../../tree/4c08919bb151553b150b94ae51825517bc2cd460/)\n\n### Stripe Integration\n\n[1 - Getting Started](../../tree/249af4dcc7cbc5496aa0ebca17c3a501021cb5e2/)\n\n[2 - Create Stripe Customer](../../tree/0a835b238f834758ba54db1c6d4978f517dccdc6/)\n\n[3 - Payment Method View & Stripe JS](../../tree/08aab3440a89cea22be0a1053b106b49d8d52f08/)\n\n[4 - Improving Payment Method Form](../../tree/ca4245aabaacc0f3c0f7e6e77902f0312a30686e/)\n\n[5 - Improving Payment Method Form Part 2](../../tree/0ff716c8a8bda2605cf349b19705d46798bb5d1b/)\n\n[6 - Reusable Stripe Module](../../tree/291073b86363a63cb588305e9c258dddc5cad949/)\n\n[7 - Add Card to Customer with Stripe](../../tree/1193c2a22da5e591aca057a4f153fdc3388c23fd/)\n\n[8 - Save Card in Django](../../tree/606f73653342ce361400a8fdddd8f0d917d6552f/)\n\n[9 - Charge the Customer](../../tree/0d4fba2c11c8bf3d4b116c4e619ffb6c41a161de/)\n\n[10 - Putting it All Together](../../tree/252524c4b46a2bad8da4cc000af0234a0227cf11/)\n\n[11 - Guest Card Checkout](../../tree/78924c3cc4ed3f3ed809a69d40a9320f423e5676/)\n\n[12 - Changing Payment Methods](../../tree/90830de29bd3bfcf948527b2fd456f27be37e14c/)\n\n[13 - Improve Card UI - Part 1](../../tree/c1a67d9c6d1c29065d1b09a771e14a7b5a0e8fc2/)\n\n[14 - Improve Card UI - Part 2](../../tree/c1a67d9c6d1c29065d1b09a771e14a7b5a0e8fc2/)\n\n### Mailchimp Integration \n\n[3 - Setup API Keys](../../tree/f540e03ebff55371f40b971d7fed439d5af886bf/)\n\n[4 - Marketing App](../../tree/4de0f03100f566797a6ac3a2de6b7764169aad24/)\n\n[5 - Mailchimp Class Part 1](../../tree/7ac2eb8e4d747fe7cc4e94c2f01ad87da9b01395/)\n\n[6 - Mailchimp Class Part 2](../../tree/26cd4fe4c3b3b1dff4426aae260578a551c5854a/)\n\n[7 - Mailchimp Class Part 3](../../tree/08dfcb3f273e0993c935372b91b5a47e66ac77c1/)\n\n[8 - Django & Mailchimp](../../tree/128499e857cf64b03a64106eb808b7177d272400/)\n\n[9 - User Email Marketing Preference View](../../tree/73756bab33f261106b9489afe1815f8a6377126e)\n\n[10 - Mailchimp Webhook Handler](../../tree/a6d88a985e21dcd926acf7fb06808459493ff0b9)\n\n\n### Go Live\n\n1 - Local vs Production Environments (no code)\n\n[2 - New Settings Module](../../tree/f776fc8227c5717b7982274d5de2a12676ab835b/)\n\n[3 - Multiple Settings Modules](../../tree/95542fffb0f225e281557d9616fb8caae85f1a06/)\n\n[4 - Prepare for HTTPs](../../tree/b772608670c45d6654a84b6b0dd014bd6cacc104/)\n\n[5 - The gitignore File](../../tree/0dc38fd34caa8c82850cbab6509b7357b53d904e/)\n\n[6 - Requirements File](../../tree/aaad5cda6f3a3170b6b9430d97db11e84ff191c2/)\n\n[7 - Setup Git Version Control](../../tree/f65d67029ebad9a22f6e63ef66170e533a385f2e/)\n\n[8 - Deploy to Heroku](../../tree/a2041155d977f6d0451aa6220fec0f664bc0cb06/)\n\n[9 - AWS S3 for Static Files](../../tree/90044ca398bbe3b06440d937dc7ea0a645ec593b/)\n\n[10 - Add Custom Domain & HTTPs on Heroku](../../tree/3689bfcd72670fa59ceaa864d58927f2c2fc53d7/)\n\n[11 - Live Environment Variables](../../tree/e3210c4ae568e5e1e48a1d70ad2e9b67cf83aa63/)\n\n[12 - Error Views and Templates](../../tree/764a8acba104c60676d83574baf7c0c0806501ad/)\n\n[13 - Setup Email to Help Solve Server Errors](../../tree/b151d182dc5ae1e380c2959a09a8eb6e2fe2fcc8/)\n\n[14 - Using Heroku Locally](../../tree/6c24c03aaf84a4fb02d9cc855815ab0e581798ff)\n\n\n### Account & Settings\n\n[1 - User Account Home](../../tree/e56ea8420170c40b420780a48cbf1087a5081525/)\n\n[2 - Naming & Dropdown](../../tree/dc1dd608ef6407d11b4d5b5e2784220fbe8d1ff4/)\n\n[3 - Account Bootstrap Cards](../../tree/c07ba032b597191f043a4ac9cd75d10ee840afcb/)\n\n[4 - Link Account Bootstrap Cards](../../tree/287fbca8d84c1a9112e6cb3adeba1c8a15693fcc/)\n\n[5 - Password Reset and Change](../../tree/55d62beec3b7374e955df8b9b6e6ddbde5997abc/)\n\n[6 - send_email and get_template](../../tree/e3c86dec0b7b985c8b1d403786d0f7a201f2767b/)\n\n[7 - Email Activation](../../tree/30f9aa0d6605014b52f80b85d139597ef6b0fcf6/)\n\n[8 - Custom QuerySet for Confirmable Activations](../../tree/4fe792b8d5e868a813f8b521cda2660fe61048ed/)\n\n[9 - Email Activation View](../../tree/0904726b55184994ac180bc0c0d55edb2a97feaa/)\n\n[10 - Email Reactivation](../../tree/3b9e78cece5c834043bd41b319a78109badf2253/)\n\n[11 - Improved Login Form & View](../../tree/359119ff0efdb482ec1e6133877ef251e3a4ebf5/)\n\n[12 - Login Form for Confirmation Emails](../../tree/a7f53f7598259f711f62957a4588dc187895e07d/)\n\n[13 - Upgrading the Guest Checkout Form](../../tree/58cac4150c5c5b724feb2f92e795ded4c162e7df/)\n\n[14 - Edit Account Details](../../tree/c471c3a04f46e7b851197de6a217fa6a68ec67b7/)\n\n[15 - User Product History View](../../tree/e50e38a7f01c9348866a92e8c7e2e772ba229763/)\n\n[16 - Orders & Order Detail](../../tree/e92f5c4ac8413fc9988510b0889a5a582cbae462/)\n\n[17 - Final Addresses on Order](../../tree/d076db0f36de01abe10e0474ac09606e33800c44/)\n\n[18 - Addresses List View](../../tree/065d6e0fd246aa1510b835d6eb6bf732e104fc8d/)\n\n[19 and 20 - Update & Create Addresses Part 1 & 2](../../tree/a89b4cd06d42648b7920a301d7c70969838b9732/)\n\n### Selling Digital Items\n\n[1 - Digital Products & Cart](../../tree/69f842b8e19470eba122a5566a2da5d23880d388/)\n\n[2 - Shipping-less Checkout](../../tree/14cae3f833034abaf0190259851a09a40efdbc65/)\n\n[3 - Product Purchases](../../tree/49bb74466bd5da3464c2cb608d150336ac2eba48/)\n\n[4 - Handling Products Being Purchased](../../tree/3cfa6c4d7ffbbd83b8246fc7984bb0f8bb448ea9/)\n\n[5 - Display of Refunded Items](../../tree/c2d95bcf338b69eec962cff6aa92a409ad204ec3/)\n\n[6 - Library View](../../tree/4d1f98e4c81c9229945a1a3342297b4f52e680d1/)\n\n[7 - Library View for Products Only](../../tree/f1e3b4618699c73034e1ac85f4bf27ba4025879a/)\n\n[8 - Product File Model](../../tree/1e74caa60b3b6f52ced214a5169e111ac8399e2a/)\n\n[9 - Changing File Field Storage to Protected Location](../../tree/a7cfdd8849d8bc22d78f1ce565b653ba32967262/)\n\n[10 - Download Product File Part 1](../../tree/e3463e00d6257726d77dcf3ad72caa77e89ed1db/)\n\n[11 - Download Product File Part 2](../../tree/91cb57960416e4ab5701f0a2cc4e7b158f47985f/)\n\n[12 - Perform the File Download](../../tree/6d92ca188e18eca8d4d4b7e1b017a010300e8c11/)\n\n[13 - Checking Download Permissions](../../tree/fe631500b7a4f69ab48b513cbf5d5be89d5a5e5c/)\n\n[14 - In Library Display Part 1](../../tree/4f1b64f1df2b67d98bf8a0d81dc57947409ad2ea)\n\n[15 - In Library Display Part 2 with Ajax](../../tree/46be780b0f0dd524d6eb4bbea63c9f0b2c4b9b7c)\n\n[16 - AWS S3 File Upload](../../tree/96d664722a95dab2895313ef3731c84093d3596d/)\n\n[17 - Fixing the Upload Path](../../tree/75c4e175bf0c4516a6ee91e2f1a7280f998ba6bd/)\n\n[18 - Creating the AWS Download Class](../../tree/d1d5cb5820d813a87d184b9eb2c34b0ff54d3c76/)\n\n[19 - Using the AWS Download Client](../../tree/a879fcc03d0225e343212b17d4c6dcb43578fdc7/)\n\n[20 - A Custom Filename](../../tree/ed23c9b95d7b84de9447bcfbeacfd35d4cfdcd08/)\n\n\n### Graphs and Sales\n\n[1 - Setup the View](../../tree/2b65b93648d4211e64cc02022a0988a96ac53b9f/)\n\n[2 - Add Context for the Order Data](../../tree/f6e5671c5c9170f3e0fdd3427acb0c49b3f60751/)\n\n[3 - Intuitive Recent Order Total](../../tree/50326ef1c082d7bcdbe9351938043b4af28f68b7/)\n\n[4 - Aggregate & Annotate](../../tree/0438bd0af6b4559fd1b80b9456a32e5b2262c6d4/)\n\n[5 - Get Data by Custom QuerySet](../../tree/8bdec3c85ec8b3a842816efbc4d80223a6d862dd/)\n\n[6 - Intro to Datetime Module](../../tree/b9f8bb1775c8037326ba3a095a224a88cf6a0775/)\n\n[7 - Filter by Range of Time](../../tree/0a8a304296f926ad0bba4fa66dff566b7e20ecbb/)\n\n[8 - Chart-js Intro](../../tree/bd9c8861e58feb5dc2ce13103a1aa21c29e7638b/)\n\n[9 - Using Ajax to Render Charts](../../tree/a60c2fb9476111de483a5fcda4c7262a10f66392/)\n\n[10 - Display True Data](../../tree/dd8a626fbb6dc43efc0799f652a808f03b7542f8/)\n\n[11 - Cleanup](../../tree/fe478427f789ff2ed9110e8e3739d6e9975fe714/)\n\n[12 - Inline Js to External](../../tree/f827bac20fc98a85ff84232ed3ea4ec4ea877f56/)\n"
  },
  {
    "path": "ecommerce.code-workspace",
    "content": "{\n\t\"folders\": [\n\t\t{\n\t\t\t\"path\": \".\"\n\t\t}\n\t],\n\t\"settings\": {}\n}"
  },
  {
    "path": "ecommerce.sublime-project",
    "content": "{\n\t\"folders\":\n\t[\n\t\t{\n\t\t\t\"path\": \".\"\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "ecommerce.sublime-workspace",
    "content": "{\n\t\"auto_complete\":\n\t{\n\t\t\"selected_items\":\n\t\t[\n\t\t\t[\n\t\t\t\t\"pos\",\n\t\t\t\t\"postal_code\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"add\",\n\t\t\t\t\"address_line_2\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"line\",\n\t\t\t\t\"line1\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"is\",\n\t\t\t\t\"is_done\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"ship\",\n\t\t\t\t\"shipping_address\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"bil\",\n\t\t\t\t\"billing_address_id\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"Bil\",\n\t\t\t\t\"BillingProfile\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"Bill\",\n\t\t\t\t\"BillingProfileManager\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"obj\",\n\t\t\t\t\"order_obj\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"order\",\n\t\t\t\t\"order_obj\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"billing\",\n\t\t\t\t\"billing_profile\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"car\",\n\t\t\t\t\"cart_removal_qs\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"gues\",\n\t\t\t\t\"guest_email_id\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"cl\",\n\t\t\t\t\"cleaned_data\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"bill\",\n\t\t\t\t\"billing_profile\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"next\",\n\t\t\t\t\"next_post\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"is_\",\n\t\t\t\t\"is_safe_url\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"user\",\n\t\t\t\t\"user_checkout\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"de\",\n\t\t\t\t\"Decimal\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"nu\",\n\t\t\t\t\"num1\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"cart\",\n\t\t\t\t\"cart_obj\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"ran\",\n\t\t\t\t\"random_string_generator\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"pr\",\n\t\t\t\t\"product_id\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"Pr\",\n\t\t\t\t\"ProductDetailSlugView\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"prd\",\n\t\t\t\t\"product_id\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"new\",\n\t\t\t\t\"new_obj\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"Car\",\n\t\t\t\t\"CartManager\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"tag\",\n\t\t\t\t\"tag_set\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"drop\",\n\t\t\t\t\"dropdown-menu\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"nav\",\n\t\t\t\t\"navbar\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"get\",\n\t\t\t\t\"get_object_or_404\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"fea\",\n\t\t\t\t\"featured\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"file\",\n\t\t\t\t\"filename\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"conta\",\n\t\t\t\t\"contact_form\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"con\",\n\t\t\t\t\"contact_form\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"mar\",\n\t\t\t\t\"margin-bottom\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"en\",\n\t\t\t\t\"environ\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"image\",\n\t\t\t\t\"image_path\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"err\",\n\t\t\t\t\"errMsg\\tlet\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"in\",\n\t\t\t\t\"instanceof\\tkeyword\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"Vid\",\n\t\t\t\t\"VideoManager\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"Vide\",\n\t\t\t\t\"VideoQuerySet\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"q\",\n\t\t\t\t\"query\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"quer\",\n\t\t\t\t\"query\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"u\",\n\t\t\t\t\"unique_slug_generator\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"col-\",\n\t\t\t\t\"col-sm-12\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"h\",\n\t\t\t\t\"homeImageList\\tproperty\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"se\",\n\t\t\t\t\"searchQuery\\tproperty\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"r\",\n\t\t\t\t\"routeSub\\tproperty\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"Av\",\n\t\t\t\t\"ActivatedRoute\\talias\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"p\",\n\t\t\t\t\"push\\tmethod\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"max\",\n\t\t\t\t\"max-height\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"margin-\",\n\t\t\t\t\"margin-bottom\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"min\",\n\t\t\t\t\"min-height\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"by\",\n\t\t\t\t\"bypassSecurityTrustResourceUrl\\tmethod\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"Pip\",\n\t\t\t\t\"PipeTransform\\talias\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"imp\",\n\t\t\t\t\"implements\\tkeyword\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"cons\",\n\t\t\t\t\"console\\tvar\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"rou\",\n\t\t\t\t\"RouterModule\\talias\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"Rou\",\n\t\t\t\t\"RouterModule\\talias\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"fu\",\n\t\t\t\t\"function\\tkeyword\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"bas\",\n\t\t\t\t\"basil3\\tlet\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"login\",\n\t\t\t\t\"loginUrl\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"lo\",\n\t\t\t\t\"login\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"data\",\n\t\t\t\t\"dataId\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"gen\",\n\t\t\t\t\"generateEditForm\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"cfe-\",\n\t\t\t\t\"cfe-media-edit\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"auth\",\n\t\t\t\t\"author\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"aut\",\n\t\t\t\t\"author\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"text\",\n\t\t\t\t\"textarea\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"form\",\n\t\t\t\t\"formData\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"object\",\n\t\t\t\t\"objectId\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"co\",\n\t\t\t\t\"contentTxt\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"content\",\n\t\t\t\t\"contentHolder\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"html\",\n\t\t\t\t\"htmlStart_\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"per\",\n\t\t\t\t\"permission_classes\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"a\",\n\t\t\t\t\"authentication\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"re\",\n\t\t\t\t\"responseJSON\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"res\",\n\t\t\t\t\"responseData\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"fo\",\n\t\t\t\t\"formResponse\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"max-\",\n\t\t\t\t\"max-height\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"time\",\n\t\t\t\t\"timestamp\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"like\",\n\t\t\t\t\"likeUrl\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"cu\",\n\t\t\t\t\"customersDjango\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"Lis\",\n\t\t\t\t\"ListView\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"save\",\n\t\t\t\t\"save_path\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"email\",\n\t\t\t\t\"email_message\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"inb\",\n\t\t\t\t\"inbox_item_list\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"ea\",\n\t\t\t\t\"email_message\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"ema\",\n\t\t\t\t\"email_message\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"acc\",\n\t\t\t\t\"access_secret\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"blog\",\n\t\t\t\t\"blog-list\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"BlogList\",\n\t\t\t\t\"blogListController\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"font\",\n\t\t\t\t\"font-size\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"img\",\n\t\t\t\t\"img_r\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"sel\",\n\t\t\t\t\"sel_soup\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"web\",\n\t\t\t\t\"webdriver\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"my\",\n\t\t\t\t\"my_num_list\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"my_\",\n\t\t\t\t\"my_num_list\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"str\",\n\t\t\t\t\"str\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"Post\",\n\t\t\t\t\"PostSerializer\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"query\",\n\t\t\t\t\"queryset\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"read\",\n\t\t\t\t\"read_time_min\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"rea\",\n\t\t\t\t\"read_time_minutes\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"count\",\n\t\t\t\t\"count_words\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"cont\",\n\t\t\t\t\"content_type\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"Co\",\n\t\t\t\t\"CommentForm\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"Commen\",\n\t\t\t\t\"CommentForm\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"H\",\n\t\t\t\t\"HttpResponseRedirect\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"Comm\",\n\t\t\t\t\"CommentManager\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"parent\",\n\t\t\t\t\"parent_qs\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"parent_\",\n\t\t\t\t\"parent_id\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"Ht\",\n\t\t\t\t\"HttpResponseRedirect\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"obje\",\n\t\t\t\t\"objects\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"pare\",\n\t\t\t\t\"parent_id\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"comm\",\n\t\t\t\t\"CommentManager\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"Com\",\n\t\t\t\t\"Comment\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"cle\",\n\t\t\t\t\"clean_parent_id\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"COmm\",\n\t\t\t\t\"CommentManager\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"conten\",\n\t\t\t\t\"content_type\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"conte\",\n\t\t\t\t\"contentItem\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"mark\",\n\t\t\t\t\"markedContent\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"titl\",\n\t\t\t\t\"titleItem\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"tit\",\n\t\t\t\t\"titleValue\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"use\",\n\t\t\t\t\"username\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"get_o\",\n\t\t\t\t\"get_object\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"usr\",\n\t\t\t\t\"username\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"get_obj\",\n\t\t\t\t\"get_object_or_404\"\n\t\t\t]\n\t\t]\n\t},\n\t\"buffers\":\n\t[\n\t],\n\t\"build_system\": \"\",\n\t\"build_system_choices\":\n\t[\n\t],\n\t\"build_varint\": \"\",\n\t\"command_palette\":\n\t{\n\t\t\"height\": 87.0,\n\t\t\"last_filter\": \"mark\",\n\t\t\"selected_items\":\n\t\t[\n\t\t\t[\n\t\t\t\t\"mark\",\n\t\t\t\t\"Markdown Preview: Preview in Browser\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"instal\",\n\t\t\t\t\"Package Control: Install Package\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"ins\",\n\t\t\t\t\"Package Control: Install Package\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"pack\",\n\t\t\t\t\"Package Control: Install Package\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"mar\",\n\t\t\t\t\"Markdown Preview: Preview in Browser\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"markd\",\n\t\t\t\t\"Markdown Preview: Preview in Browser\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"markdown\",\n\t\t\t\t\"Markdown Preview: Preview in Browser\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"\",\n\t\t\t\t\"Convert Case: Lower Case\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"package\",\n\t\t\t\t\"Package Control: List Packages\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"install\",\n\t\t\t\t\"Package Control: Install Package\"\n\t\t\t]\n\t\t],\n\t\t\"width\": 485.0\n\t},\n\t\"console\":\n\t{\n\t\t\"height\": 125.0,\n\t\t\"history\":\n\t\t[\n\t\t]\n\t},\n\t\"distraction_free\":\n\t{\n\t\t\"menu_visible\": true,\n\t\t\"show_minimap\": false,\n\t\t\"show_open_files\": false,\n\t\t\"show_tabs\": false,\n\t\t\"side_bar_visible\": false,\n\t\t\"status_bar_visible\": false\n\t},\n\t\"expanded_folders\":\n\t[\n\t\t\"/Users/cfe/Dev/ecommerce\"\n\t],\n\t\"file_history\":\n\t[\n\t\t\"/Users/cfe/Dev/ecommerce/src/ecommerce/settings.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/addresses/admin.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/addresses/forms.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/addresses/models.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/billing/models.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/addresses/templates/addresses/form.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/ecommerce/urls.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/addresses/views.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/accounts/views.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/orders/models.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/addresses/templates/addresses/prev_addresses.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/carts/templates/carts/checkout.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/carts/templates/carts/checkout-done.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/carts/urls.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/parse_git_log.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/carts/views.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/README.md\",\n\t\t\"/Users/cfe/Dev/ecommerce/parsed_log.md\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/billing/admin.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/accounts/templates/accounts/snippets/form.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/accounts/forms.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/accounts/models.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/accounts/admin.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/notes/checkout_process.md\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/ecommerce/views.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/templates/base/navbar.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/ecommerce/forms.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/templates/auth/login.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/carts/models.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/ecommerce/utils.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/products/models.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/tags/models.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/orders/admin.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/carts/templates/carts/home.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/products/utils.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/orders/utils.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/templates/base/css.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/products/views.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/products/templates/products/detail.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/products/templates/products/snippets/update-cart.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/carts/admin.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/search/urls.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/tags/admin.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/tags/shell_commands.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/search/templates/search/view.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/search/templates/search/snippets/search-form.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/search/views.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/search/models.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/search/templates/search/search_form.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/templates/bootstrap/example.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/templates/base.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/templates/home_page.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/products/templates/products/list.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/templates/auth/register.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/templates/bootstrap-section/base.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/templates/contact/view.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/products/urls.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/products/templates/products/snippets/card.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/products/admin.py\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/templates/base/js.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/products/templates/products/featured-detail.html\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/products/understanding_crud.md\",\n\t\t\"/Users/cfe/Dev/ecommerce/src/static_my_proj/css/main.css\",\n\t\t\"/Users/cfe/Dev/cfe-s3-upload/backend/src/templates/upload.html\",\n\t\t\"/Users/cfe/Dev/cfe-s3-upload/backend/src/cfehome/urls.py\",\n\t\t\"/Users/cfe/Dev/cfe-s3-upload/backend/src/files/config_aws.py\",\n\t\t\"/Users/cfe/Dev/cfe-s3-upload/backend/src/cfehome/settings/base.py\",\n\t\t\"/Users/cfe/Dev/cfe-s3-upload/backend/src/cfehome/settings/local.py\",\n\t\t\"/Users/cfe/Dev/cfe-s3-upload/backend/src/cfehome/settings/production.py\",\n\t\t\"/Users/cfe/Dev/cfe-s3-upload/backend/src/credentials.py\",\n\t\t\"/Users/cfe/Dev/cfe-s3-upload/backend/src/cfehome/credentials.py\",\n\t\t\"/Users/cfe/Dev/django-s3-upload/credentials.py\",\n\t\t\"/Users/cfe/Dev/django-s3-upload/src/credentials.py\",\n\t\t\"/Users/cfe/Dev/basics/src/templates/posts/listview.html\",\n\t\t\"/Users/cfe/Dev/basics/src/posts/migrations/0006_auto_20170727_1653.py\",\n\t\t\"/Users/cfe/Dev/basics/src/pages/models.py\",\n\t\t\"/Users/cfe/Dev/basics/src/cfebasic/urls.py\",\n\t\t\"/Users/cfe/Dev/basics/src/templates/navbar.html\",\n\t\t\"/Users/cfe/Dev/basics/src/templates/javascript.html\",\n\t\t\"/Users/cfe/Dev/basics/src/templates/base.html\",\n\t\t\"/Users/cfe/Dev/basics/src/templates/contact.html\",\n\t\t\"/Users/cfe/Dev/basics/src/templates/about.html\",\n\t\t\"/Users/cfe/Dev/basics/src/templates/home.html\",\n\t\t\"/Users/cfe/Dev/basics/src/cfebasic/settings.py\",\n\t\t\"/Users/cfe/Dev/basics/src/posts/views.py\",\n\t\t\"/Users/cfe/Dev/basics/src/pages/views.py\",\n\t\t\"/Users/cfe/Dev/trydjango1-11/README.md\",\n\t\t\"/Users/cfe/Dev/trydjango1-11/LICENSE\",\n\t\t\"/Users/cfe/Dev/trydjango1-11/.gitignore\",\n\t\t\"/Users/cfe/Dev/trydjango1-11/requirements.txt\",\n\t\t\"/Users/cfe/Dev/trydjango1-11/src/muypicky/settings/__init__.py\",\n\t\t\"/Users/jmitch/Dropbox/cfe/v2/src/accounts/signals.py\",\n\t\t\"/Users/jmitch/Dropbox/cfe/v2/src/analytics/models.py\",\n\t\t\"/Users/jmitch/Dropbox/cfe/v2/src/accounts/views.py\",\n\t\t\"/Users/cfe/Dev/geo2/.gitignore\",\n\t\t\"/Users/cfe/Dev/geo2/src\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/.env\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/tryangular/settings/base.py\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/tryangular/aws/utils.py\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/tryangular/aws/conf.py\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/tryangular/wsgi.py\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/tryangular/__init__.py\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/tryangular/settings/local.py\",\n\t\t\"/Users/cfe/Dev/djangular/client/src/app/home/home.component.ts\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/videos/models.py\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/videos/api/serializers.py\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/tryangular/settings/production.py\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/videos/migrations/0006_auto_20170426_2258.py\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/tryangular/aws/__init__.py\",\n\t\t\"/Users/cfe/Downloads/credentials (1).csv\",\n\t\t\"/Users/cfe/Dev/djangular/.gitignore\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/tryangular/settings/__init__.py\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/runtime.txt\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/tryangular/old_settings.py\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/staticheroku/mediaheroku/images/blank.txt\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/staticheroku/mediaheroku/blank.txt\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/requirements.txt\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/mediaheroku/blank.txt\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/mediaheroku/blank\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/Procfile\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/.gitignore\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/videos/utils.py\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/templates/500.html\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/templates/404.html\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/tryangular/urls.py\",\n\t\t\"/Users/cfe/Dev/djangular/backend/src/videos/api/urls.py\",\n\t\t\"/Users/cfe/Dev/djangular/client/src/app/video-detail/video-detail.component.html\",\n\t\t\"/Users/cfe/Dev/djangular/client/src/app/search/search.component.ts\"\n\t],\n\t\"find\":\n\t{\n\t\t\"height\": 40.0\n\t},\n\t\"find_in_files\":\n\t{\n\t\t\"height\": 132.0,\n\t\t\"where_history\":\n\t\t[\n\t\t\t\"/Users/jmitch/Dropbox/cfe/v2/src\",\n\t\t\t\"/Users/cfe/Dev/djangular/client/src/app\",\n\t\t\t\"/Users/jmitch/Desktop/ecommerce-2/src\",\n\t\t\t\"/Users/jmitch/Dropbox/projects/kpj\",\n\t\t\t\"/Users/jmitch/Dropbox/projects/kpj/kpj\",\n\t\t\t\"/Users/jmitch/Dropbox/projects/\",\n\t\t\t\"/Users/jmitch/Dropbox/projects/kpj/kpj\",\n\t\t\t\"<open files>\",\n\t\t\t\"/Users/jmitch/Dropbox/projects/kpj/kpj\",\n\t\t\t\"/Users/jmitch/Dropbox/projects/kpj\",\n\t\t\t\"/Users/jmitch/Dropbox/cfe/src\"\n\t\t]\n\t},\n\t\"find_state\":\n\t{\n\t\t\"case_sensitive\": false,\n\t\t\"find_history\":\n\t\t[\n\t\t\t\"Login\",\n\t\t\t\"Session\",\n\t\t\t\"fileUploadComplete\",\n\t\t\t\"$.alert\",\n\t\t\t\"uploadFile\",\n\t\t\t\"courseId\",\n\t\t\t\"username\",\n\t\t\t\"file_bucket\",\n\t\t\t\".send\",\n\t\t\t\"end_session\",\n\t\t\t\"user_logged_in\",\n\t\t\t\"geoip\",\n\t\t\t\"object_viewed\",\n\t\t\t\"console.log\",\n\t\t\t\"videoListDefaultImage\",\n\t\t\t\"\\\"assets/\",\n\t\t\t\"from\",\n\t\t\t\"jquery\",\n\t\t\t\"login\",\n\t\t\t\".load-comments\",\n\t\t\t\"load-comments\",\n\t\t\t\"parent()\",\n\t\t\t\">Edit\",\n\t\t\t\"edit\",\n\t\t\t\"formatErrorMsg\",\n\t\t\t\"authUsername\",\n\t\t\t\"owner\",\n\t\t\t\"getComments\",\n\t\t\t\"likes\",\n\t\t\t\"url\",\n\t\t\t\"crispy\",\n\t\t\t\"Comment\",\n\t\t\t\"charts\",\n\t\t\t\"markdown\",\n\t\t\t\"comment\",\n\t\t\t\"reportlab\",\n\t\t\t\"$http\",\n\t\t\t\"get_transactions\",\n\t\t\t\"ProductUpdateView\",\n\t\t\t\"delete all\",\n\t\t\t\"jmitch-#\",\n\t\t\t\"AddressSelectFormView\",\n\t\t\t\"order_address\",\n\t\t\t\"\\\"\",\n\t\t\t\"item_it\",\n\t\t\t\"trydjango18\",\n\t\t\t\"questions_notification\",\n\t\t\t\"app.task\",\n\t\t\t\"needs_rep\",\n\t\t\t\"sendgrid\",\n\t\t\t\"celerybeat-schedule.db\",\n\t\t\t\"get_next_lecture\",\n\t\t\t\"lecture_quiz_result\",\n\t\t\t\"quiz\",\n\t\t\t\"url\",\n\t\t\t\"reverse\",\n\t\t\t\"module-box\",\n\t\t\t\"slug\",\n\t\t\t\"lang\",\n\t\t\t\"send_mail\",\n\t\t\t\"get_user\",\n\t\t\t\"ppe_4\",\n\t\t\t\"as_view\",\n\t\t\t\"\\\"join\\\"\",\n\t\t\t\"saftey\",\n\t\t\t\"Saftey Trianing i\",\n\t\t\t\"Training on new pesticides prior to first use\",\n\t\t\t\"transaction\",\n\t\t\t\"render_to\",\n\t\t\t\"render_to_pdf\",\n\t\t\t\"render_to\",\n\t\t\t\"DeleteView\",\n\t\t\t\"welcome_\",\n\t\t\t\"welcome\",\n\t\t\t\"all.html\",\n\t\t\t\"$.ajax\",\n\t\t\t\"ajax\",\n\t\t\t\"wistia\",\n\t\t\t\"upload\",\n\t\t\t\"review\",\n\t\t\t\"review now\",\n\t\t\t\"review_chemicals\",\n\t\t\t\"lectures_admin\",\n\t\t\t\"upload_bulk\",\n\t\t\t\"ChemicalsViewAdmin\",\n\t\t\t\"filter(active=F\",\n\t\t\t\"active\",\n\t\t\t\"LectureQuizAdminView\",\n\t\t\t\"formview\",\n\t\t\t\"$.ajax\",\n\t\t\t\"ajax\",\n\t\t\t\"clean\",\n\t\t\t\"keep\",\n\t\t\t\"questionanswer\",\n\t\t\t\"initial\",\n\t\t\t\"get_lecture\",\n\t\t\t\"slug\",\n\t\t\t\"LectureDetailView\",\n\t\t\t\"get_lecture\",\n\t\t\t\"get_next_lecture\",\n\t\t\t\"lecture_quiz\",\n\t\t\t\"edit_lecture\",\n\t\t\t\"single_lecture\",\n\t\t\t\"single\",\n\t\t\t\"form.as\",\n\t\t\t\"question.as\",\n\t\t\t\"question\",\n\t\t\t\"method\",\n\t\t\t\"csv\",\n\t\t\t\"ceu\",\n\t\t\t\"login\",\n\t\t\t\"easy\",\n\t\t\t\"grand\",\n\t\t\t\"pricing\",\n\t\t\t\"cost\",\n\t\t\t\"paginator\",\n\t\t\t\"question\",\n\t\t\t\"lecturequestion\",\n\t\t\t\"question\",\n\t\t\t\"next\",\n\t\t\t\"take_quiz\",\n\t\t\t\"after \",\n\t\t\t\"href\",\n\t\t\t\"take_quiz\",\n\t\t\t\"start\",\n\t\t\t\"Coding\",\n\t\t\t\"Coding For Entrepreneurs\",\n\t\t\t\"Coding for Entrepreneurs\"\n\t\t],\n\t\t\"highlight\": false,\n\t\t\"in_selection\": false,\n\t\t\"preserve_case\": false,\n\t\t\"regex\": false,\n\t\t\"replace_history\":\n\t\t[\n\t\t\t\"\\\"/static/ang/assets/\",\n\t\t\t\".cfe-load-comments\",\n\t\t\t\"jmitch=#\",\n\t\t\t\"'\",\n\t\t\t\"ecommerce2\",\n\t\t\t\"Control Guidance Solutions, LLC\",\n\t\t\t\"class=\\\"fa fa-check fa-2x\\\"\",\n\t\t\t\"img/apple-touch-icon-152.png\",\n\t\t\t\"{})\",\n\t\t\t\"render(request,\",\n\t\t\t\"render(\",\n\t\t\t\")\",\n\t\t\t\"render(request,\",\n\t\t\t\"Coding For Entrepreneurs\",\n\t\t\t\"CodingForEntrepreneurs.com\",\n\t\t\t\"Coding For Entrepreneurs\",\n\t\t\t\"CodingForEntrepreneurs.com\"\n\t\t],\n\t\t\"reverse\": false,\n\t\t\"show_context\": false,\n\t\t\"use_buffer2\": false,\n\t\t\"whole_word\": false,\n\t\t\"wrap\": true\n\t},\n\t\"groups\":\n\t[\n\t\t{\n\t\t\t\"sheets\":\n\t\t\t[\n\t\t\t]\n\t\t}\n\t],\n\t\"incremental_find\":\n\t{\n\t\t\"height\": 40.0\n\t},\n\t\"input\":\n\t{\n\t\t\"height\": 52.0\n\t},\n\t\"layout\":\n\t{\n\t\t\"cells\":\n\t\t[\n\t\t\t[\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\t1,\n\t\t\t\t1\n\t\t\t]\n\t\t],\n\t\t\"cols\":\n\t\t[\n\t\t\t0.0,\n\t\t\t1.0\n\t\t],\n\t\t\"rows\":\n\t\t[\n\t\t\t0.0,\n\t\t\t1.0\n\t\t]\n\t},\n\t\"menu_visible\": true,\n\t\"output.doc\":\n\t{\n\t\t\"height\": 0.0\n\t},\n\t\"output.find_results\":\n\t{\n\t\t\"height\": 508.0\n\t},\n\t\"pinned_build_system\": \"\",\n\t\"project\": \"ecommerce.sublime-project\",\n\t\"replace\":\n\t{\n\t\t\"height\": 76.0\n\t},\n\t\"save_all_on_build\": true,\n\t\"select_file\":\n\t{\n\t\t\"height\": 0.0,\n\t\t\"last_filter\": \"\",\n\t\t\"selected_items\":\n\t\t[\n\t\t\t[\n\t\t\t\t\"email\",\n\t\t\t\t\"templates/team/email_instructions.html\"\n\t\t\t]\n\t\t],\n\t\t\"width\": 0.0\n\t},\n\t\"select_project\":\n\t{\n\t\t\"height\": 0.0,\n\t\t\"last_filter\": \"\",\n\t\t\"selected_items\":\n\t\t[\n\t\t],\n\t\t\"width\": 0.0\n\t},\n\t\"select_symbol\":\n\t{\n\t\t\"height\": 0.0,\n\t\t\"last_filter\": \"\",\n\t\t\"selected_items\":\n\t\t[\n\t\t],\n\t\t\"width\": 0.0\n\t},\n\t\"selected_group\": 0,\n\t\"settings\":\n\t{\n\t},\n\t\"show_minimap\": false,\n\t\"show_open_files\": true,\n\t\"show_tabs\": true,\n\t\"side_bar_visible\": true,\n\t\"side_bar_width\": 224.0,\n\t\"status_bar_visible\": true,\n\t\"template_settings\":\n\t{\n\t}\n}\n"
  },
  {
    "path": "fasttracktojquery/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <!-- Required meta tags -->\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n\n    <!-- Bootstrap CSS -->\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n    <style>\n    /*body {\n      background-color: red;\n    }*/\n    h1 {\n      color: green;\n    }\n\n    #header-3 {\n\n    }\n    .description {\n      width: 250px;\n      height: 300px;\n      padding: 30px 10px;\n    }\n  </style>\n\n  </head>\n  <body>\n    <div class='container'>\n      <div class='row'>\n        <div class='col mx-auto'>\n          <h3>Form</h3>\n    <form class='new-content-form' method=\"POST\" action='/some/url/link'>\n      <textarea name='content' class='form-control'></textarea>\n      <input type='submit' value='Save' />\n    </form>\n  </div>\n</div>\n  </div>\n\n  <div class='formDataSubmitted'>\n\n\n  </div>\n\n\n\n\n\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n<br/>\n\n\n\n\n\n    <h1 class='header'>Hello, world!</h1>\n    <h1 class='header'>Hello, world!</h1>\n    <h1 class='header' id='header-3'>Header 3</h1>\n    <h1 class='header'>Hello, world!</h1>\n    \n    <p class='description'><a href='/abc/'>Some Link</a></p>\n    <p class='description'>Another Paragraph</p>\n    <p class='description'>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam pulvinar eros sed neque maximus, vel volutpat odio facilisis. Pellentesque convallis laoreet dapibus. Fusce sit amet elementum mauris, id fermentum risus. Integer ultrices velit at nunc egestas, vel iaculis est lobortis. Integer mattis sagittis ligula vel viverra. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce nec lectus ultricies, scelerisque nisl ut, ullamcorper libero. Aliquam at lacinia metus, sed hendrerit mi. Etiam euismod ultrices orci, non vestibulum arcu porta rhoncus. Aliquam bibendum auctor magna non consequat. Morbi varius, sapien a finibus mollis, augue enim sodales nisi, vel finibus tellus quam nec quam. Vestibulum venenatis nisl id justo molestie, ac imperdiet quam commodo.\n\nNunc finibus odio sagittis risus tincidunt hendrerit. Etiam sapien nisl, congue eget ex in, egestas scelerisque risus. Quisque odio lectus, scelerisque ac nisl ut, commodo rhoncus magna. Praesent consectetur turpis nec ante maximus, sed tristique enim ultrices. Nulla libero massa, bibendum eget semper vitae, mollis sit amet quam. Suspendisse euismod aliquam dolor at suscipit. Nullam faucibus tincidunt venenatis. Pellentesque id quam aliquam libero lacinia aliquet at id libero. Praesent ut ante ligula. Mauris quis est interdum, elementum nibh nec, condimentum odio. Suspendisse interdum sapien tortor, a efficitur elit varius sed. Phasellus eu nisl enim. Nulla ultricies feugiat eros sit amet finibus. Maecenas tellus eros, pulvinar non luctus ac, faucibus ut neque. Praesent non luctus quam.</p>\n    <!-- Optional JavaScript -->\n    <!-- jQuery first, then Popper.js, then Bootstrap JS -->\n   <script src='https://code.jquery.com/jquery-3.2.1.min.js'></script>\n<!--    <script type=\"text/javascript\">\n      $(document).ready(function(){\n          var num = 124\n          var someString = \"some string\"\n          // some_array = [num, 123, 12333, \"an so on\"]\n          var someArray = [num, 9, 12333, \"an so on\"]\n          var someBool = true // true\n          $.each(someArray, function(index, obj){\n              // console.log(index, obj)\n              // 10 % 3  == 1\n              // 9 % 3 == 0\n              if ( obj %2 == 0 && someBool) {\n                console.log(obj, \"is even\")\n              } else if (obj%3 == 0 && someBool){\n                console.log(obj, \"by 3\")\n              } else {\n                console.log(obj, \"false and/or is not even\")\n              }\n          })\n\n\n\n      }) \n\n\n   </script> -->\n\n\n\n\n\n   <!-- <script type=\"text/javascript\">\n      $(document).ready(function(){\n        // jquery is ready to roll\n        // $(selector)\n        // $('body').css(\"background-color\", \"red\")\n        var $description = $(\".description\")\n\n        // $description.css(\"height\", \"300px\").css(\"width\", \"250px\")\n        console.log($description.length) // if 1 then exists// print()\n        console.log($description.css(\"height\")) // print()\n        console.log($description.height())\n\n        // if currentElementHeight > builtInHeight\n        // add $description.css(\"overflow\", \"scroll\")\n\n\n        setTimeout(function(){\n            // $('body').css(\"background-color\", \"red\")\n            $('h1').css(\"color\", \"purple\")\n            $('h1:nth-child(2)').text(\"Hello again!\")\n            $('#header-3').text(\"Hello again header 3!\")\n            $(\".header\").css(\"background-color\", \"green\").css(\"padding\", \"30px\")\n        }, 2000) // in ms\n      })\n   </script> -->\n\n\n\n\n\n\n\n   <!-- <script type=\"text/javascript\">\n      $(document).ready(function(){\n        var $descriptionItems = $(\".description\")\n        // console.log($descriptionItems.length) // 0, 1, 2\n\n        $.each($descriptionItems, function(index, obj){\n          var item = $(this) \n          var actualHeight = item[0].scrollHeight\n          var shouldBeHeight = item.height()\n          // console.log(actualHeight, shouldBeHeight)\n          if (actualHeight > shouldBeHeight + 50){\n            item.css(\"overflow-y\", \"scroll\")\n          }\n          // console.log(index, item.height())\n          // console.log(index, obj)\n        })\n\n\n\n        var header3 = $(\"#header-3\")\n        header3.click(function(event){\n          var $this = $(this)\n          console.log($this)\n          console.log(event)\n          window.location.href = 'http://www.google.com/'\n        })\n\n\n        var descriptionLinks = $(\".description a\")\n        descriptionLinks.click(function(event){\n          console.log(event)\n          event.preventDefault()\n          var $this = $(this)\n          var href = $this.attr(\"href\")\n          console.log(href)\n          alert(href)\n          window.location.href =href\n\n        })\n      })\n   </script>\n\n -->\n\n\n\n\n\n\n\n\n\n <script type=\"text/javascript\">\n    $(document).ready(function(){\n      var contentForm = $(\".new-content-form\")\n      contentForm.submit(function(event){\n        event.preventDefault()\n        var $this = $(this)\n        //console.log(contentForm.serialize())\n        var textAreaContent = $this.find('textarea')\n        // console.log(textAreaContent.attr(\"name\"))\n        //console.log(textAreaContent.val())\n        var formMethod = $this.attr(\"method\") // contentForm.attr(\"method\")\n        var formAction = $this.attr(\"action\")\n        var data = {\n            \"content\": textAreaContent.val(),\n            \"method\": formMethod,\n            \"action\": formAction\n        }\n\n        $('.formDataSubmitted').text(textAreaContent.val() + \" method is \" + formMethod)\n\n        textAreaContent.val(\"\")\n\n\n        // $.ajax({\n        //   url:\n        //   method:\n        //   data:\n        // })\n\n      })\n\n    })\n\n\n </script>\n\n\n\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js\" integrity=\"sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4\" crossorigin=\"anonymous\"></script>\n    <script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js\" integrity=\"sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1\" crossorigin=\"anonymous\"></script>\n  </body>\n</html>"
  },
  {
    "path": "notes/checkout_process.md",
    "content": "# Checkout Process\n\n1. Cart -> Checkout View\n    ?\n    - Login/Register or Enter an Email (as Guest)\n    - Shipping Address\n    - Billing Info\n        - Billing Address\n        - Credit Card / Payment\n\n2. Billing App/Component\n    - Billing Profile\n        - User or Email (Guest Email)\n        - generate payment processor token (Stripe or Braintree)\n\n\n3. Orders / Invoices Component\n    - Connecting the Billing Profile\n    - Shipping / Billing Address\n    - Cart\n    - Status -- Shipped? Cancelled?\n\n\n\n4. Backup Fixtures\n    python manage.py dumpdata products  --format json --indent 4 > products/fixtures/products.json"
  },
  {
    "path": "parse_git_log.py",
    "content": "'''\nThis document helps use parse our git commits so we \ncan make them more easily readable and clickable\nin our Readme.\n'''\n\nimport os\nimport datetime\nimport git # pip install GitPython\n\n\nrepo = git.Repo(os.getcwd())\n\nmaster = repo.head.reference\n\nwith open(\"parsed_log.md\", \"w+\") as parsed_log:\n\tfor commit in master.log():\n\t\tif \"commit\" in commit.message:\n\t\t\tcommit_mess = commit.message.replace(\"commit: \", \"\").replace(\"commit (initial): \", \"\")\n\t\t\tline = \"[{message}](../../tree/{commit}/)\".format(message=commit_mess, commit=commit.newhexsha)\n\t\t\tparsed_log.write(line)\n\t\t\tparsed_log.write(\"\\n\\n\")\n"
  },
  {
    "path": "pyvenv.cfg",
    "content": "home = /Library/Frameworks/Python.framework/Versions/3.8/bin\ninclude-system-site-packages = false\nversion = 3.8.2\n"
  },
  {
    "path": "src/.gitignore",
    "content": "# Not Ready for Production\n# marketing/\n\n.env\n\n\necommerce/settings/local.py\necommerce/aws/ignore2.py\n\n.DS_STORE\n*.sublime-project\nfasttracktojquery/\n\n\n\n# Virtualenv related\nbin/\ninclude/\npip-selfcheck.json\n\n# Django related \n\n# src/<yourproject>/settings/local.py\n# static-cdn/  # any collected static files \n\n\n# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n.hypothesis/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# pyenv\n.python-version\n\n# celery beat schedule file\ncelerybeat-schedule\n\n# SageMath parsed files\n*.sage.py\n\n# Environments\n.env\n.venv\nenv/\nvenv/\nENV/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/"
  },
  {
    "path": "src/Procfile",
    "content": "web: gunicorn ecommerce.wsgi"
  },
  {
    "path": "src/accounts/__init__.py",
    "content": ""
  },
  {
    "path": "src/accounts/admin.py",
    "content": "from django.contrib import admin\nfrom django.contrib.auth import get_user_model\nfrom django.contrib.auth.models import Group\nfrom django.contrib.auth.admin import UserAdmin as BaseUserAdmin\n\n\n\nfrom .forms import UserAdminCreationForm, UserAdminChangeForm\nfrom .models import GuestEmail, EmailActivation\n\nUser = get_user_model()\n\n\n\nclass UserAdmin(BaseUserAdmin):\n    # The forms to add and change user instances\n    form = UserAdminChangeForm\n    add_form = UserAdminCreationForm\n\n    # The fields to be used in displaying the User model.\n    # These override the definitions on the base UserAdmin\n    # that reference specific fields on auth.User.\n    list_display = ('email', 'admin')\n    list_filter = ('admin', 'staff', 'is_active')\n    fieldsets = (\n        (None, {'fields': ('full_name', 'email', 'password')}),\n       # ('Full name', {'fields': ()}),\n        ('Permissions', {'fields': ('admin', 'staff', 'is_active',)}),\n    )\n    # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin\n    # overrides get_fieldsets to use this attribute when creating a user.\n    add_fieldsets = (\n        (None, {\n            'classes': ('wide',),\n            'fields': ('email', 'password1', 'password2')}\n        ),\n    )\n    search_fields = ('email', 'full_name',)\n    ordering = ('email',)\n    filter_horizontal = ()\n\n\nadmin.site.register(User, UserAdmin)\n\n# Remove Group Model from admin. We're not using it.\nadmin.site.unregister(Group)\n\n\n\nclass EmailActivationAdmin(admin.ModelAdmin):\n    search_fields = ['email']\n    class Meta:\n        model = EmailActivation\n\n\nadmin.site.register(EmailActivation, EmailActivationAdmin)\n\n\nclass GuestEmailAdmin(admin.ModelAdmin):\n    search_fields = ['email']\n    class Meta:\n        model = GuestEmail\n\n\nadmin.site.register(GuestEmail, GuestEmailAdmin)"
  },
  {
    "path": "src/accounts/apps.py",
    "content": "from django.apps import AppConfig\n\n\nclass AccountsConfig(AppConfig):\n    name = 'accounts'\n"
  },
  {
    "path": "src/accounts/forms.py",
    "content": "from django import forms\nfrom django.contrib.auth import authenticate, login, get_user_model\nfrom django.contrib.auth.forms import ReadOnlyPasswordHashField\nfrom django.core.urlresolvers import reverse\nfrom django.utils.safestring import mark_safe\n\nUser = get_user_model()\n\nfrom .models import EmailActivation, GuestEmail\n\n\nclass ReactivateEmailForm(forms.Form):\n    email       = forms.EmailField()\n\n    def clean_email(self):\n        email = self.cleaned_data.get('email')\n        qs = EmailActivation.objects.email_exists(email) \n        if not qs.exists():\n            register_link = reverse(\"register\")\n            msg = \"\"\"This email does not exists, would you like to <a href=\"{link}\">register</a>?\n            \"\"\".format(link=register_link)\n            raise forms.ValidationError(mark_safe(msg))\n        return email\n\n\nclass UserAdminCreationForm(forms.ModelForm):\n    \"\"\"A form for creating new users. Includes all the required\n    fields, plus a repeated password.\"\"\"\n    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)\n    password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)\n\n    class Meta:\n        model = User\n        fields = ('full_name', 'email',) #'full_name',)\n\n    def clean_password2(self):\n        # Check that the two password entries match\n        password1 = self.cleaned_data.get(\"password1\")\n        password2 = self.cleaned_data.get(\"password2\")\n        if password1 and password2 and password1 != password2:\n            raise forms.ValidationError(\"Passwords don't match\")\n        return password2\n\n    def save(self, commit=True):\n        # Save the provided password in hashed format\n        user = super(UserAdminCreationForm, self).save(commit=False)\n        user.set_password(self.cleaned_data[\"password1\"])\n        if commit:\n            user.save()\n        return user\n\n\n\nclass UserDetailChangeForm(forms.ModelForm):\n    full_name = forms.CharField(label='Name', required=False, widget=forms.TextInput(attrs={\"class\": 'form-control'}))\n\n    class Meta:\n        model = User\n        fields = ['full_name']\n\n\n\nclass UserAdminChangeForm(forms.ModelForm):\n    \"\"\"A form for updating users. Includes all the fields on\n    the user, but replaces the password field with admin's\n    password hash display field.\n    \"\"\"\n    password = ReadOnlyPasswordHashField()\n\n    class Meta:\n        model = User\n        fields = ('full_name', 'email', 'password', 'is_active', 'admin')\n\n    def clean_password(self):\n        # Regardless of what the user provides, return the initial value.\n        # This is done here, rather than on the field, because the\n        # field does not have access to the initial value\n        return self.initial[\"password\"]\n\n\n\nclass GuestForm(forms.ModelForm):\n    #email    = forms.EmailField()\n    class Meta:\n        model = GuestEmail\n        fields = [\n            'email'\n        ]\n\n    def __init__(self, request, *args, **kwargs):\n        self.request = request\n        super(GuestForm, self).__init__(*args, **kwargs)\n\n    def save(self, commit=True):\n        # Save the provided password in hashed format\n        obj = super(GuestForm, self).save(commit=False)\n        if commit:\n            obj.save()\n            request = self.request\n            request.session['guest_email_id'] = obj.id\n        return obj\n\n\n\nclass LoginForm(forms.Form):\n    email    = forms.EmailField(label='Email')\n    password = forms.CharField(widget=forms.PasswordInput)\n\n    def __init__(self, request, *args, **kwargs):\n        self.request = request\n        super(LoginForm, self).__init__(*args, **kwargs)\n\n    def clean(self):\n        request = self.request\n        data = self.cleaned_data\n        email  = data.get(\"email\")\n        password  = data.get(\"password\")\n        qs = User.objects.filter(email=email)\n        if qs.exists():\n            # user email is registered, check active/\n            not_active = qs.filter(is_active=False)\n            if not_active.exists():\n                ## not active, check email activation\n                link = reverse(\"account:resend-activation\")\n                reconfirm_msg = \"\"\"Go to <a href='{resend_link}'>\n                resend confirmation email</a>.\n                \"\"\".format(resend_link = link)\n                confirm_email = EmailActivation.objects.filter(email=email)\n                is_confirmable = confirm_email.confirmable().exists()\n                if is_confirmable:\n                    msg1 = \"Please check your email to confirm your account or \" + reconfirm_msg.lower()\n                    raise forms.ValidationError(mark_safe(msg1))\n                email_confirm_exists = EmailActivation.objects.email_exists(email).exists()\n                if email_confirm_exists:\n                    msg2 = \"Email not confirmed. \" + reconfirm_msg\n                    raise forms.ValidationError(mark_safe(msg2))\n                if not is_confirmable and not email_confirm_exists:\n                    raise forms.ValidationError(\"This user is inactive.\")\n        user = authenticate(request, username=email, password=password)\n        if user is None:\n            raise forms.ValidationError(\"Invalid credentials\")\n        login(request, user)\n        self.user = user\n        return data\n\n    # def form_valid(self, form):\n    #     request = self.request\n    #     next_ = request.GET.get('next')\n    #     next_post = request.POST.get('next')\n    #     redirect_path = next_ or next_post or None\n    #     email  = form.cleaned_data.get(\"email\")\n    #     password  = form.cleaned_data.get(\"password\")\n        \n    #     print(user)\n    #     if user is not None:\n    #         if not user.is_active:\n    #             print('inactive user..')\n    #             messages.success(request, \"This user is inactive\")\n    #             return super(LoginView, self).form_invalid(form)\n    #         login(request, user)\n    #         user_logged_in.send(user.__class__, instance=user, request=request)\n    #         try:\n    #             del request.session['guest_email_id']\n    #         except:\n    #             pass\n    #         if is_safe_url(redirect_path, request.get_host()):\n    #             return redirect(redirect_path)\n    #         else:\n    #             return redirect(\"/\")\n    #     return super(LoginView, self).form_invalid(form)\n\n\nclass RegisterForm(forms.ModelForm):\n    \"\"\"A form for creating new users. Includes all the required\n    fields, plus a repeated password.\"\"\"\n    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)\n    password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)\n\n    class Meta:\n        model = User\n        fields = ('full_name', 'email',) #'full_name',)\n\n    def clean_password2(self):\n        # Check that the two password entries match\n        password1 = self.cleaned_data.get(\"password1\")\n        password2 = self.cleaned_data.get(\"password2\")\n        if password1 and password2 and password1 != password2:\n            raise forms.ValidationError(\"Passwords don't match\")\n        return password2\n\n    def save(self, commit=True):\n        # Save the provided password in hashed format\n        user = super(RegisterForm, self).save(commit=False)\n        user.set_password(self.cleaned_data[\"password1\"])\n        user.is_active = False # send confirmation email via signals\n        # obj = EmailActivation.objects.create(user=user)\n        # obj.send_activation_email()\n        if commit:\n            user.save()\n        return user\n\n\n\n"
  },
  {
    "path": "src/accounts/migrations/0001_initial.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-09 21:27\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    initial = True\n\n    dependencies = [\n    ]\n\n    operations = [\n        migrations.CreateModel(\n            name='User',\n            fields=[\n                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),\n                ('password', models.CharField(max_length=128, verbose_name='password')),\n                ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),\n                ('email', models.EmailField(max_length=255, unique=True)),\n                ('active', models.BooleanField(default=True)),\n                ('staff', models.BooleanField(default=False)),\n                ('admin', models.BooleanField(default=False)),\n                ('timestamp', models.DateTimeField(auto_now_add=True)),\n            ],\n            options={\n                'abstract': False,\n            },\n        ),\n        migrations.CreateModel(\n            name='GuestEmail',\n            fields=[\n                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),\n                ('email', models.EmailField(max_length=254)),\n                ('active', models.BooleanField(default=True)),\n                ('update', models.DateTimeField(auto_now=True)),\n                ('timestamp', models.DateTimeField(auto_now_add=True)),\n            ],\n        ),\n    ]\n"
  },
  {
    "path": "src/accounts/migrations/0002_user_full_name.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-09 21:44\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('accounts', '0001_initial'),\n    ]\n\n    operations = [\n        migrations.AddField(\n            model_name='user',\n            name='full_name',\n            field=models.CharField(blank=True, max_length=255, null=True),\n        ),\n    ]\n"
  },
  {
    "path": "src/accounts/migrations/0003_user_is_active.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-10-23 22:47\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('accounts', '0002_user_full_name'),\n    ]\n\n    operations = [\n        migrations.AddField(\n            model_name='user',\n            name='is_active',\n            field=models.BooleanField(default=True),\n        ),\n    ]\n"
  },
  {
    "path": "src/accounts/migrations/0004_remove_user_active.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-10-24 17:09\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('accounts', '0003_user_is_active'),\n    ]\n\n    operations = [\n        migrations.RemoveField(\n            model_name='user',\n            name='active',\n        ),\n    ]\n"
  },
  {
    "path": "src/accounts/migrations/0005_emailactivation.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-10-24 18:13\nfrom __future__ import unicode_literals\n\nfrom django.conf import settings\nfrom django.db import migrations, models\nimport django.db.models.deletion\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('accounts', '0004_remove_user_active'),\n    ]\n\n    operations = [\n        migrations.CreateModel(\n            name='EmailActivation',\n            fields=[\n                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),\n                ('email', models.EmailField(max_length=254)),\n                ('key', models.CharField(blank=True, max_length=120, null=True)),\n                ('activated', models.BooleanField(default=False)),\n                ('forced_expired', models.BooleanField(default=False)),\n                ('expires', models.IntegerField(default=7)),\n                ('timestamp', models.DateTimeField(auto_now_add=True)),\n                ('update', models.DateTimeField(auto_now=True)),\n                ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),\n            ],\n        ),\n    ]\n"
  },
  {
    "path": "src/accounts/migrations/__init__.py",
    "content": ""
  },
  {
    "path": "src/accounts/models.py",
    "content": "from datetime import timedelta\nfrom django.conf import settings\nfrom django.core.urlresolvers import reverse\nfrom django.db import models\nfrom django.db.models import Q\nfrom django.db.models.signals import pre_save, post_save\nfrom django.contrib.auth.models import (\n    AbstractBaseUser, BaseUserManager\n)\n\nfrom django.core.mail import send_mail\nfrom django.template.loader import get_template\nfrom django.utils import timezone\n\nfrom ecommerce.utils import random_string_generator, unique_key_generator\n#send_mail(subject, message, from_email, recipient_list, html_message)\n\nDEFAULT_ACTIVATION_DAYS = getattr(settings, 'DEFAULT_ACTIVATION_DAYS', 7)\n\nclass UserManager(BaseUserManager):\n    def create_user(self, email, full_name=None, password=None, is_active=True, is_staff=False, is_admin=False):\n        if not email:\n            raise ValueError(\"Users must have an email address\")\n        if not password:\n            raise ValueError(\"Users must have a password\")\n        user_obj = self.model(\n            email = self.normalize_email(email),\n            full_name=full_name\n        )\n        user_obj.set_password(password) # change user password\n        user_obj.staff = is_staff\n        user_obj.admin = is_admin\n        user_obj.is_active = is_active\n        user_obj.save(using=self._db)\n        return user_obj\n\n    def create_staffuser(self, email,full_name=None, password=None):\n        user = self.create_user(\n                email,\n                full_name=full_name,\n                password=password,\n                is_staff=True\n        )\n        return user\n\n    def create_superuser(self, email, full_name=None, password=None):\n        user = self.create_user(\n                email,\n                full_name=full_name,\n                password=password,\n                is_staff=True,\n                is_admin=True\n        )\n        return user\n\n\nclass User(AbstractBaseUser):\n    email       = models.EmailField(max_length=255, unique=True)\n    full_name   = models.CharField(max_length=255, blank=True, null=True)\n    is_active   = models.BooleanField(default=True) # can login \n    staff       = models.BooleanField(default=False) # staff user non superuser\n    admin       = models.BooleanField(default=False) # superuser \n    timestamp   = models.DateTimeField(auto_now_add=True)\n    # confirm     = models.BooleanField(default=False)\n    # confirmed_date     = models.DateTimeField(default=False)\n\n    USERNAME_FIELD = 'email' #username\n    # USERNAME_FIELD and password are required by default\n    REQUIRED_FIELDS = [] #['full_name'] #python manage.py createsuperuser\n\n    objects = UserManager()\n\n    def __str__(self):\n        return self.email\n\n    def get_full_name(self):\n        if self.full_name:\n            return self.full_name\n        return self.email\n\n    def get_short_name(self):\n        return self.email\n\n    def has_perm(self, perm, obj=None):\n        return True\n\n    def has_module_perms(self, app_label):\n        return True\n\n    @property\n    def is_staff(self):\n        if self.is_admin:\n            return True\n        return self.staff\n\n    @property\n    def is_admin(self):\n        return self.admin\n\n    # @property\n    # def is_active(self):\n    #     return self.active\n\n\nclass EmailActivationQuerySet(models.query.QuerySet):\n    def confirmable(self):\n        now = timezone.now()\n        start_range = now - timedelta(days=DEFAULT_ACTIVATION_DAYS)\n        # does my object have a timestamp in here\n        end_range = now\n        return self.filter(\n                activated = False,\n                forced_expired = False\n              ).filter(\n                timestamp__gt=start_range,\n                timestamp__lte=end_range\n              )\n\n\nclass EmailActivationManager(models.Manager):\n    def get_queryset(self):\n        return EmailActivationQuerySet(self.model, using=self._db)\n\n    def confirmable(self):\n        return self.get_queryset().confirmable()\n\n    def email_exists(self, email):\n        return self.get_queryset().filter(\n                    Q(email=email) | \n                    Q(user__email=email)\n                ).filter(\n                    activated=False\n                )\n\n\nclass EmailActivation(models.Model):\n    user            = models.ForeignKey(User)\n    email           = models.EmailField()\n    key             = models.CharField(max_length=120, blank=True, null=True)\n    activated       = models.BooleanField(default=False)\n    forced_expired  = models.BooleanField(default=False)\n    expires         = models.IntegerField(default=7) # 7 Days\n    timestamp       = models.DateTimeField(auto_now_add=True)\n    update          = models.DateTimeField(auto_now=True)\n\n    objects = EmailActivationManager()\n\n    def __str__(self):\n        return self.email\n\n    def can_activate(self):\n        qs = EmailActivation.objects.filter(pk=self.pk).confirmable() # 1 object\n        if qs.exists():\n            return True\n        return False\n\n    def activate(self):\n        if self.can_activate():\n            # pre activation user signal\n            user = self.user\n            user.is_active = True\n            user.save()\n            # post activation signal for user\n            self.activated = True\n            self.save()\n            return True\n        return False\n\n    def regenerate(self):\n        self.key = None\n        self.save()\n        if self.key is not None:\n            return True\n        return False\n\n    def send_activation(self):\n        if not self.activated and not self.forced_expired:\n            if self.key:\n                base_url = getattr(settings, 'BASE_URL', 'https://www.pythonecommerce.com')\n                key_path = reverse(\"account:email-activate\", kwargs={'key': self.key}) # use reverse\n                path = \"{base}{path}\".format(base=base_url, path=key_path)\n                context = {\n                    'path': path,\n                    'email': self.email\n                }\n                txt_ = get_template(\"registration/emails/verify.txt\").render(context)\n                html_ = get_template(\"registration/emails/verify.html\").render(context)\n                subject = '1-Click Email Verification'\n                from_email = settings.DEFAULT_FROM_EMAIL\n                recipient_list = [self.email]\n                sent_mail = send_mail(\n                            subject,\n                            txt_,\n                            from_email,\n                            recipient_list,\n                            html_message=html_,\n                            fail_silently=False,\n                    )\n                return sent_mail\n        return False\n\n\n\ndef pre_save_email_activation(sender, instance, *args, **kwargs):\n    if not instance.activated and not instance.forced_expired:\n        if not instance.key:\n            instance.key = unique_key_generator(instance)\n\npre_save.connect(pre_save_email_activation, sender=EmailActivation)\n\n\ndef post_save_user_create_reciever(sender, instance, created, *args, **kwargs):\n    if created:\n        obj = EmailActivation.objects.create(user=instance, email=instance.email)\n        obj.send_activation()\n\npost_save.connect(post_save_user_create_reciever, sender=User)\n\n\n\nclass GuestEmail(models.Model):\n    email       = models.EmailField()\n    active      = models.BooleanField(default=True)\n    update      = models.DateTimeField(auto_now=True)\n    timestamp   = models.DateTimeField(auto_now_add=True)\n\n    def __str__(self):\n        return self.email"
  },
  {
    "path": "src/accounts/passwords/__init__.py",
    "content": ""
  },
  {
    "path": "src/accounts/passwords/urls.py",
    "content": "# accounts.passwords.urls.py \nfrom django.conf.urls import url\nfrom django.contrib.auth import views as auth_views\n\nurlpatterns  = [\n        url(r'^password/change/$', \n                auth_views.PasswordChangeView.as_view(), \n                name='password_change'),\n        url(r'^password/change/done/$',\n                auth_views.PasswordChangeDoneView.as_view(), \n                name='password_change_done'),\n        url(r'^password/reset/$', \n                auth_views.PasswordResetView.as_view(), \n                name='password_reset'),\n        url(r'^password/reset/done/$', \n                auth_views.PasswordResetDoneView.as_view(), \n                name='password_reset_done'),\n        url(r'^password/reset/(?P<uidb64>[0-9A-Za-z_\\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', \n                auth_views.PasswordResetConfirmView.as_view(), \n                name='password_reset_confirm'),\n        url(r'^password/reset/complete/$', \n                auth_views.PasswordResetCompleteView.as_view(), \n                name='password_reset_complete'),\n]"
  },
  {
    "path": "src/accounts/signals.py",
    "content": "from django.dispatch import Signal\n\n\nuser_logged_in = Signal(providing_args=['instance', 'request'])"
  },
  {
    "path": "src/accounts/templates/accounts/detail-update-view.html",
    "content": "{% extends \"base.html\" %}\n\n\n{% block content %}\n<div class='col-12 col-md-6 mx-auto'>\n{% if title %}<h1 class='my-3'>{{ title }}</h1>{% endif %}\n<form method='POST' action='{% if action_url %}{{ action_url }}{% endif %}'> {% csrf_token %}\n    {% if next_url %}\n    <input type='hidden' name='next' value='{{ next_url }}' />\n    {% endif %}\n  {{ form.as_p }}\n  <label for='email'>Email</label>\n  <input type='text' id='email' class='form-control disabled' value='{{ request.user.email }}' disabled=\"disabled\" /><span class='help-text'>Cannot change email</span><br/>\n  <button type='submit' class='btn btn-default my-3'>Save</button>\n  <a href='{% url \"password_change\" %}'>Change Password</a>\n</form>\n</div>\n{% endblock %}"
  },
  {
    "path": "src/accounts/templates/accounts/home.html",
    "content": "{% extends \"base.html\" %}\n\n{% block content %}\n<div class='row'>\n<div class='col-12'>\n<h1>Account</h1>\n<hr/>\n</div>\n<div class='col-12 col-md-3 my-3'>\n    <div class=\"card\">\n      <div class=\"card-body\">\n        <h4 class=\"card-title\">Support</h4>\n            <div class='list-group'>\n                <a class='list-group-item' href='{% url \"about\" %}'>About</a>\n                <a class='list-group-item' href='{% url \"contact\" %}'>Contact</a>\n            </div>\n      </div>\n    </div>\n</div>\n\n\n\n<div class='col-12 col-md-3 my-3' id='billing'>\n    <div class=\"card\">\n      <div class=\"card-body\">\n        <h4 class=\"card-title\">Billing</h4>\n            <div class='list-group'>\n                <a class='list-group-item' href='{% url \"orders:list\" %}'>Orders</a>\n                <a class='list-group-item' href='{% url \"billing-payment-method\" %}'>Payment Methods</a>\n                <a class='list-group-item' href='{% url \"addresses\" %}'>Addresses</a>\n                \n                \n            </div>\n      </div>\n    </div>\n</div>\n\n\n<div class='col-12 col-md-3 my-3'>\n    <div class=\"card\">\n      <div class=\"card-body\">\n        <h4 class=\"card-title\">Account Details</h4> \n            <div class='list-group'>\n                <a class='list-group-item' href='{% url \"account:user-update\" %}'>Update Details</a>\n                <a class='list-group-item' href='{% url \"password_change\" %}'>Change Password</a>\n                <a class='list-group-item' href='{% url \"library\" %}'>Library</a>\n                \n            </div>\n\n      </div>\n    </div>\n</div>\n\n\n<div class='col-12 col-md-3 my-3'>\n    <div class=\"card\">\n      <div class=\"card-body\">\n        <h4 class=\"card-title\">Preferences</h4> \n            <div class='list-group'>\n                <a class='list-group-item' href='{% url \"marketing-pref\" %}'>Email Marketing</a>\n                \n            </div>\n\n      </div>\n    </div>\n</div>\n\n\n<div class='col-12 col-md-3 my-3'>\n    <div class=\"card\">\n      <div class=\"card-body\">\n        <h4 class=\"card-title\">History</h4> \n              <div class='list-group'>\n                <a class='list-group-item' href='{% url \"account:user-product-history\" %}'>Products</a>\n            </div>\n      </div>\n    </div>\n</div>\n\n\n</div>\n\n\n{% endblock %}"
  },
  {
    "path": "src/accounts/templates/accounts/login.html",
    "content": "{% extends \"base.html\" %}\n\n{% block content %}\n<h1>Login</h1>\n    <form method='POST'> {% csrf_token %}\n      {{ form }}\n      <button type='submit' class='btn btn-default'>Submit</button>\n    </form>\n\n{% endblock %}"
  },
  {
    "path": "src/accounts/templates/accounts/register.html",
    "content": "{% extends \"base.html\" %}\n\n{% block content %}\n    <h1>Register</h1>\n    <form method='POST'> {% csrf_token %}\n      {{ form }}\n      <button type='submit' class='btn btn-default'>Submit</button>\n    </form>\n\n{% endblock %}"
  },
  {
    "path": "src/accounts/templates/accounts/snippets/form.html",
    "content": "<form method='POST' action='{% if action_url %}{{ action_url }}{% else %}{% url \"login\" %}{% endif %}'> {% csrf_token %}\n    {% if next_url %}\n    <input type='hidden' name='next' value='{{ next_url }}' />\n    {% endif %}\n  {{ form }}\n  <button type='submit' class='btn btn-default'>Submit</button>\n</form>"
  },
  {
    "path": "src/accounts/tests.py",
    "content": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "src/accounts/urls.py",
    "content": "from django.conf.urls import url\n\nfrom products.views import UserProductHistoryView\nfrom .views import (\n        AccountHomeView, \n        AccountEmailActivateView,\n        UserDetailUpdateView\n        )\n\nurlpatterns = [\n    url(r'^$', AccountHomeView.as_view(), name='home'),\n    url(r'^details/$', UserDetailUpdateView.as_view(), name='user-update'),\n    url(r'history/products/$', UserProductHistoryView.as_view(), name='user-product-history'),\n    url(r'^email/confirm/(?P<key>[0-9A-Za-z]+)/$', \n            AccountEmailActivateView.as_view(), \n            name='email-activate'),\n    url(r'^email/resend-activation/$', \n            AccountEmailActivateView.as_view(), \n            name='resend-activation'),\n]\n\n# account/email/confirm/asdfads/ -> activation view"
  },
  {
    "path": "src/accounts/views.py",
    "content": "from django.contrib.auth import authenticate, login, get_user_model\nfrom django.contrib.auth.decorators import login_required\nfrom django.contrib.auth.mixins import LoginRequiredMixin\nfrom django.contrib import messages\nfrom django.core.urlresolvers import reverse\nfrom django.utils.decorators import method_decorator\nfrom django.views.generic import CreateView, FormView, DetailView, View, UpdateView\nfrom django.views.generic.edit import FormMixin\nfrom django.http import HttpResponse\nfrom django.shortcuts import render,redirect\nfrom django.utils.http import is_safe_url\nfrom django.utils.safestring import mark_safe\n\nfrom ecommerce.mixins import NextUrlMixin, RequestFormAttachMixin\nfrom .forms import LoginForm, RegisterForm, GuestForm, ReactivateEmailForm, UserDetailChangeForm\nfrom .models import GuestEmail, EmailActivation\nfrom .signals import user_logged_in\n\n\n# @login_required # /accounts/login/?next=/some/path/\n# def account_home_view(request):\n#     return render(request, \"accounts/home.html\", {})\n\n\n#LoginRequiredMixin,\nclass AccountHomeView(LoginRequiredMixin, DetailView):\n    template_name = 'accounts/home.html'\n    def get_object(self):\n        return self.request.user\n\n\n\nclass AccountEmailActivateView(FormMixin, View):\n    success_url = '/login/'\n    form_class = ReactivateEmailForm\n    key = None\n    def get(self, request, key=None, *args, **kwargs):\n        self.key = key\n        if key is not None:\n            qs = EmailActivation.objects.filter(key__iexact=key)\n            confirm_qs = qs.confirmable()\n            if confirm_qs.count() == 1:\n                obj = confirm_qs.first()\n                obj.activate()\n                messages.success(request, \"Your email has been confirmed. Please login.\")\n                return redirect(\"login\")\n            else:\n                activated_qs = qs.filter(activated=True)\n                if activated_qs.exists():\n                    reset_link = reverse(\"password_reset\")\n                    msg = \"\"\"Your email has already been confirmed\n                    Do you need to <a href=\"{link}\">reset your password</a>?\n                    \"\"\".format(link=reset_link)\n                    messages.success(request, mark_safe(msg))\n                    return redirect(\"login\") \n        context = {'form': self.get_form(),'key': key}\n        return render(request, 'registration/activation-error.html', context)\n\n    def post(self, request, *args, **kwargs):\n        # create form to receive an email\n        form = self.get_form()\n        if form.is_valid():\n            return self.form_valid(form)\n        else:\n            return self.form_invalid(form)\n\n    def form_valid(self, form):\n        msg = \"\"\"Activation link sent, please check your email.\"\"\"\n        request = self.request\n        messages.success(request, msg)\n        email = form.cleaned_data.get(\"email\")\n        obj = EmailActivation.objects.email_exists(email).first()\n        user = obj.user \n        new_activation = EmailActivation.objects.create(user=user, email=email)\n        new_activation.send_activation()\n        return super(AccountEmailActivateView, self).form_valid(form)\n\n    def form_invalid(self, form):\n        context = {'form': form, \"key\": self.key }\n        return render(self.request, 'registration/activation-error.html', context)\n\n\nclass GuestRegisterView(NextUrlMixin,  RequestFormAttachMixin, CreateView):\n    form_class = GuestForm\n    default_next = '/register/'\n\n    def get_success_url(self):\n        return self.get_next_url()\n\n    def form_invalid(self, form):\n        return redirect(self.default_next)\n\n\nclass LoginView(NextUrlMixin, RequestFormAttachMixin, FormView):\n    form_class = LoginForm\n    success_url = '/'\n    template_name = 'accounts/login.html'\n    default_next = '/'\n\n    def form_valid(self, form):\n        next_path = self.get_next_url()\n        return redirect(next_path)\n\n\n\n\nclass RegisterView(CreateView):\n    form_class = RegisterForm\n    template_name = 'accounts/register.html'\n    success_url = '/login/'\n\n\n\n\nclass UserDetailUpdateView(LoginRequiredMixin, UpdateView):\n    form_class = UserDetailChangeForm\n    template_name = 'accounts/detail-update-view.html'\n\n    def get_object(self):\n        return self.request.user\n\n    def get_context_data(self, *args, **kwargs):\n        context = super(UserDetailUpdateView, self).get_context_data(*args, **kwargs)\n        context['title'] = 'Change Your Account Details'\n        return context\n\n    def get_success_url(self):\n        return reverse(\"account:home\")\n\n\n# def login_page(request):\n#     form = LoginForm(request.POST or None)\n#     context = {\n#         \"form\": form\n#     }\n#     next_ = request.GET.get('next')\n#     next_post = request.POST.get('next')\n#     redirect_path = next_ or next_post or None\n#     if form.is_valid():\n#         username  = form.cleaned_data.get(\"username\")\n#         password  = form.cleaned_data.get(\"password\")\n#         user = authenticate(request, username=username, password=password)\n#         if user is not None:\n#             login(request, user)\n#             try:\n#                 del request.session['guest_email_id']\n#             except:\n#                 pass\n#             if is_safe_url(redirect_path, request.get_host()):\n#                 return redirect(redirect_path)\n#             else:\n#                 return redirect(\"/\")\n#         else:\n#             # Return an 'invalid login' error message.\n#             print(\"Error\")\n#     return render(request, \"accounts/login.html\", context)\n\n# User = get_user_model()\n# def register_page(request):\n#     form = RegisterForm(request.POST or None)\n#     context = {\n#         \"form\": form\n#     }\n#     if form.is_valid():\n#         form.save()\n#     return render(request, \"accounts/register.html\", context)"
  },
  {
    "path": "src/addresses/__init__.py",
    "content": ""
  },
  {
    "path": "src/addresses/admin.py",
    "content": "from django.contrib import admin\n\nfrom .models import Address\n\nadmin.site.register(Address)"
  },
  {
    "path": "src/addresses/apps.py",
    "content": "from django.apps import AppConfig\n\n\nclass AddressesConfig(AppConfig):\n    name = 'addresses'\n"
  },
  {
    "path": "src/addresses/forms.py",
    "content": "from django import forms\n\nfrom .models import Address\n\n\nclass AddressForm(forms.ModelForm):\n    \"\"\"\n    User-related CRUD form\n    \"\"\"\n    class Meta:\n        model = Address\n        fields = [\n            'nickname',\n            'name',\n            #'billing_profile',\n            'address_type',\n            'address_line_1',\n            'address_line_2',\n            'city',\n            'country',\n            'state',\n            'postal_code'\n        ]\n\n\n\n\nclass AddressCheckoutForm(forms.ModelForm):\n    \"\"\"\n    User-related checkout address create form\n    \"\"\"\n    class Meta:\n        model = Address\n        fields = [\n            'nickname',\n            'name',\n            #'billing_profile',\n            #'address_type',\n            'address_line_1',\n            'address_line_2',\n            'city',\n            'country',\n            'state',\n            'postal_code'\n        ]\n\n"
  },
  {
    "path": "src/addresses/migrations/0001_initial.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-28 23:42\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\nimport django.db.models.deletion\n\n\nclass Migration(migrations.Migration):\n\n    initial = True\n\n    dependencies = [\n        ('billing', '0002_auto_20170928_2052'),\n    ]\n\n    operations = [\n        migrations.CreateModel(\n            name='Address',\n            fields=[\n                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),\n                ('address_type', models.CharField(choices=[('billing', 'Billing'), ('shipping', 'Shipping')], max_length=120)),\n                ('address_line_1', models.CharField(max_length=120)),\n                ('address_line_2', models.CharField(blank=True, max_length=120, null=True)),\n                ('city', models.CharField(max_length=120)),\n                ('country', models.CharField(default='United States of America', max_length=120)),\n                ('state', models.CharField(max_length=120)),\n                ('postal_code', models.CharField(max_length=120)),\n                ('billing_profile', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='billing.BillingProfile')),\n            ],\n        ),\n    ]\n"
  },
  {
    "path": "src/addresses/migrations/0002_auto_20171107_0055.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-11-07 00:55\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('addresses', '0001_initial'),\n    ]\n\n    operations = [\n        migrations.AddField(\n            model_name='address',\n            name='name',\n            field=models.CharField(blank=True, help_text='Shipping to? Who is it for?', max_length=120, null=True),\n        ),\n        migrations.AddField(\n            model_name='address',\n            name='nickname',\n            field=models.CharField(blank=True, help_text='Internal Reference Nickname', max_length=120, null=True),\n        ),\n        migrations.AlterField(\n            model_name='address',\n            name='address_type',\n            field=models.CharField(choices=[('billing', 'Billing address'), ('shipping', 'Shipping address')], max_length=120),\n        ),\n    ]\n"
  },
  {
    "path": "src/addresses/migrations/__init__.py",
    "content": ""
  },
  {
    "path": "src/addresses/models.py",
    "content": "from django.db import models\nfrom django.core.urlresolvers import reverse\nfrom billing.models import BillingProfile\n\nADDRESS_TYPES = (\n    ('billing', 'Billing address'),\n    ('shipping', 'Shipping address'),\n)\n\nclass Address(models.Model):\n    billing_profile = models.ForeignKey(BillingProfile)\n    name            = models.CharField(max_length=120, null=True, blank=True, help_text='Shipping to? Who is it for?')\n    nickname        = models.CharField(max_length=120, null=True, blank=True, help_text='Internal Reference Nickname')\n    address_type    = models.CharField(max_length=120, choices=ADDRESS_TYPES)\n    address_line_1  = models.CharField(max_length=120)\n    address_line_2  = models.CharField(max_length=120, null=True, blank=True)\n    city            = models.CharField(max_length=120)\n    country         = models.CharField(max_length=120, default='United States of America')\n    state           = models.CharField(max_length=120)\n    postal_code     = models.CharField(max_length=120)\n\n    def __str__(self):\n        if self.nickname:\n            return str(self.nickname)\n        return str(self.address_line_1)\n\n    def get_absolute_url(self):\n        return reverse(\"address-update\", kwargs={\"pk\": self.pk})\n\n    def get_short_address(self):\n        for_name = self.name \n        if self.nickname:\n            for_name = \"{} | {},\".format( self.nickname, for_name)\n        return \"{for_name} {line1}, {city}\".format(\n                for_name = for_name or \"\",\n                line1 = self.address_line_1,\n                city = self.city\n            ) \n\n    def get_address(self):\n        return \"{for_name}\\n{line1}\\n{line2}\\n{city}\\n{state}, {postal}\\n{country}\".format(\n                for_name = self.name or \"\",\n                line1 = self.address_line_1,\n                line2 = self.address_line_2 or \"\",\n                city = self.city,\n                state = self.state,\n                postal= self.postal_code,\n                country = self.country\n            )"
  },
  {
    "path": "src/addresses/templates/addresses/form.html",
    "content": "<form method='POST' action='{% if action_url %}{{ action_url }}{% else %}{% url \"login\" %}{% endif %}'> {% csrf_token %}\n    {% if next_url %}\n    <input type='hidden' name='next' value='{{ next_url }}' />\n    {% endif %}\n\n    {% if address_type %}\n    <input type='hidden' name='address_type' value='{{ address_type }}' />\n    {% endif %}\n  {{ form.as_p }}\n  <button type='submit' class='btn btn-default'>Submit</button>\n</form>"
  },
  {
    "path": "src/addresses/templates/addresses/list.html",
    "content": "{% extends \"base.html\" %}\n\n{% block content %}\n<div class='row'>\n<div class='col-12'>\n<h1>Address{% if object_list.count > 1%}es{% endif %} <small><a href='{% url \"address-create\" %}'>Create New</a></small></h1>\n<hr/>\n</div>\n</div>\n<div class='row'>\n        {% for obj in object_list %}\n            <div class='col-12 col-md-3 my-3'>\n                <div class=\"card\">\n                  <div class=\"card-body\">\n                    <h4 class=\"card-title\">{{ obj }}</h4> \n                     <small>{{ obj.get_address_type_display }}</small><br/>\n                     <br/>\n                     <h5>Address</h5>\n                     {{ obj.get_address|linebreaks }}\n                    \n                    <a href='{{ obj.get_absolute_url }}' class='btn btn-default'>Edit</a>\n                  </div>\n                </div>\n            </div>\n        {% empty %}\n         <p class='lead text-center'><a href='{% url \"address-create\" %}'>Create New</a></p>\n        {% endfor %}\n</div>\n{% endblock %}"
  },
  {
    "path": "src/addresses/templates/addresses/prev_addresses.html",
    "content": "{% if address_qs.exists %}\n        <form method='POST' action='{{ action_url }}'> {% csrf_token %}\n             {% if next_url %}\n            <input type='hidden' name='next' value='{{ next_url }}' />\n            {% endif %}\n            {% if address_type %}\n            <input type='hidden' name='address_type' value='{{ address_type }}' />\n            {% endif %}\n\n\n            {% for address in address_qs %}\n                <label for='address-{{ address.id }}'>\n                    <input id='address-{{ address.id }}' type='radio' name='shipping_address' value='{{ address.id }}' />\n                {{ address.get_short_address }}\n                </label><br/>\n            {% endfor %}\n            <button type='submit' class='btn btn-success'>Use Address</button>\n        </form>\n{% endif %}"
  },
  {
    "path": "src/addresses/templates/addresses/update.html",
    "content": "{% extends \"base.html\" %}\n\n{% block content %}\n\n<div class='row'>\n    <div class='col-10 mx-auto col-md-6 '>\n        {% if form.instance.address_line_1  %}\n        <h3 class='my-5'>Update Address</h3>\n        {% else %}\n        <h3 class='my-5'>Create Address</h3>\n        {% endif %}\n        <hr>\n    <form method='POST' action=''> {% csrf_token %}\n      {{ form.as_p }}\n      <button type='submit' class='btn btn-default'>Save Address</button>\n    </form>\n    </div>\n\n</div>\n\n{% endblock %}"
  },
  {
    "path": "src/addresses/tests.py",
    "content": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "src/addresses/views.py",
    "content": "from django.contrib.auth.mixins import LoginRequiredMixin\nfrom django.views.generic import ListView, UpdateView, CreateView\nfrom django.shortcuts import render, redirect\nfrom django.utils.http import is_safe_url\n# CRUD create update retrieve delete\n\nfrom billing.models import BillingProfile\nfrom .forms import AddressCheckoutForm, AddressForm\nfrom .models import Address\n\n\n\nclass AddressListView(LoginRequiredMixin, ListView):\n    template_name = 'addresses/list.html'\n\n    def get_queryset(self):\n        request = self.request\n        billing_profile, billing_profile_created = BillingProfile.objects.new_or_get(request)\n        return Address.objects.filter(billing_profile=billing_profile)\n\n\n\nclass AddressUpdateView(LoginRequiredMixin, UpdateView):\n    template_name = 'addresses/update.html'\n    form_class = AddressForm\n    success_url = '/addresses'\n    \n    def get_queryset(self):\n        request = self.request\n        billing_profile, billing_profile_created = BillingProfile.objects.new_or_get(request)\n        return Address.objects.filter(billing_profile=billing_profile)\n\n\nclass AddressCreateView(LoginRequiredMixin, CreateView):\n    template_name = 'addresses/update.html'\n    form_class = AddressForm\n    success_url = '/addresses'\n\n    def form_valid(self, form):\n        request = self.request\n        billing_profile, billing_profile_created = BillingProfile.objects.new_or_get(request)\n        instance = form.save(commit=False)\n        instance.billing_profile = billing_profile\n        instance.save()\n        return super(AddressCreateView, self).form_valid(form)\n\n    # def get_queryset(self):\n        \n    #     return Address.objects.filter(billing_profile=billing_profile)\n\n\n\n\n\n\ndef checkout_address_create_view(request):\n    form = AddressCheckoutForm(request.POST or None)\n    context = {\n        \"form\": form\n    }\n    next_ = request.GET.get('next')\n    next_post = request.POST.get('next')\n    redirect_path = next_ or next_post or None\n    if form.is_valid():\n        print(request.POST)\n        instance = form.save(commit=False)\n        billing_profile, billing_profile_created = BillingProfile.objects.new_or_get(request)\n        if billing_profile is not None:\n            address_type = request.POST.get('address_type', 'shipping')\n            instance.billing_profile = billing_profile\n            instance.address_type = address_type\n            instance.save()\n            request.session[address_type + \"_address_id\"] = instance.id\n            print(address_type + \"_address_id\")\n        else:\n            print(\"Error here\")\n            return redirect(\"cart:checkout\")\n\n        if is_safe_url(redirect_path, request.get_host()):\n            return redirect(redirect_path)\n    return redirect(\"cart:checkout\") \n\n\ndef checkout_address_reuse_view(request):\n    if request.user.is_authenticated():\n        context = {}\n        next_ = request.GET.get('next')\n        next_post = request.POST.get('next')\n        redirect_path = next_ or next_post or None\n        if request.method == \"POST\":\n            print(request.POST)\n            shipping_address = request.POST.get('shipping_address', None)\n            address_type = request.POST.get('address_type', 'shipping')\n            billing_profile, billing_profile_created = BillingProfile.objects.new_or_get(request)\n            if shipping_address is not None:\n                qs = Address.objects.filter(billing_profile=billing_profile, id=shipping_address)\n                if qs.exists():\n                    request.session[address_type + \"_address_id\"] = shipping_address\n                if is_safe_url(redirect_path, request.get_host()):\n                    return redirect(redirect_path)\n    return redirect(\"cart:checkout\") \n\n"
  },
  {
    "path": "src/analytics/__init__.py",
    "content": ""
  },
  {
    "path": "src/analytics/admin.py",
    "content": "from django.contrib import admin\n\nfrom .models import ObjectViewed, UserSession\n\n\nadmin.site.register(ObjectViewed)\n\nadmin.site.register(UserSession)"
  },
  {
    "path": "src/analytics/apps.py",
    "content": "from django.apps import AppConfig\n\n\nclass AnalyticsConfig(AppConfig):\n    name = 'analytics'\n"
  },
  {
    "path": "src/analytics/migrations/0001_initial.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-10 21:30\nfrom __future__ import unicode_literals\n\nfrom django.conf import settings\nfrom django.db import migrations, models\nimport django.db.models.deletion\n\n\nclass Migration(migrations.Migration):\n\n    initial = True\n\n    dependencies = [\n        migrations.swappable_dependency(settings.AUTH_USER_MODEL),\n        ('contenttypes', '0002_remove_content_type_name'),\n    ]\n\n    operations = [\n        migrations.CreateModel(\n            name='ObjectViewed',\n            fields=[\n                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),\n                ('ip_address', models.CharField(blank=True, max_length=220, null=True)),\n                ('object_id', models.PositiveIntegerField()),\n                ('timestamp', models.DateTimeField(auto_now_add=True)),\n                ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')),\n                ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),\n            ],\n            options={\n                'verbose_name': 'Object viewed',\n                'verbose_name_plural': 'Objects viewed',\n                'ordering': ['-timestamp'],\n            },\n        ),\n    ]\n"
  },
  {
    "path": "src/analytics/migrations/0002_usersession.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-10 22:08\nfrom __future__ import unicode_literals\n\nfrom django.conf import settings\nfrom django.db import migrations, models\nimport django.db.models.deletion\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        migrations.swappable_dependency(settings.AUTH_USER_MODEL),\n        ('analytics', '0001_initial'),\n    ]\n\n    operations = [\n        migrations.CreateModel(\n            name='UserSession',\n            fields=[\n                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),\n                ('ip_address', models.CharField(blank=True, max_length=220, null=True)),\n                ('session_key', models.CharField(blank=True, max_length=100, null=True)),\n                ('timestamp', models.DateTimeField(auto_now_add=True)),\n                ('active', models.BooleanField(default=True)),\n                ('ended', models.BooleanField(default=False)),\n                ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),\n            ],\n        ),\n    ]\n"
  },
  {
    "path": "src/analytics/migrations/__init__.py",
    "content": ""
  },
  {
    "path": "src/analytics/mixins.py",
    "content": "from .signals import object_viewed_signal\n\n\nclass ObjectViewedMixin(object):\n    def get_context_data(self, *args, **kwargs):\n        context = super(ObjectViewedMixin, self).get_context_data(*args, **kwargs)\n        request = self.request\n        instance  = context.get('object')\n        if instance:\n            object_viewed_signal.send(instance.__class__, instance=instance, request=request)\n        return context"
  },
  {
    "path": "src/analytics/models.py",
    "content": "from django.conf import settings\nfrom django.contrib.contenttypes.fields import GenericForeignKey\nfrom django.contrib.contenttypes.models import ContentType\nfrom django.contrib.sessions.models import Session\nfrom django.db import models\nfrom django.db.models.signals import pre_save, post_save\n\nfrom accounts.signals import user_logged_in\nfrom .signals import object_viewed_signal\nfrom .utils import get_client_ip\n\nUser = settings.AUTH_USER_MODEL\n\n\nFORCE_SESSION_TO_ONE = getattr(settings, 'FORCE_SESSION_TO_ONE', False)\nFORCE_INACTIVE_USER_ENDSESSION= getattr(settings, 'FORCE_INACTIVE_USER_ENDSESSION', False)\n\n\nclass ObjectViewedQuerySet(models.query.QuerySet):\n    def by_model(self, model_class, model_queryset=False):\n        c_type = ContentType.objects.get_for_model(model_class)\n        qs = self.filter(content_type=c_type)\n        if model_queryset:\n            viewed_ids = [x.object_id for x in qs]\n            return model_class.objects.filter(pk__in=viewed_ids)\n        return qs\n\nclass ObjectViewedManager(models.Manager):\n    def get_queryset(self):\n        return ObjectViewedQuerySet(self.model, using=self._db)\n\n    def by_model(self, model_class, model_queryset=False):\n        return self.get_queryset().by_model(model_class, model_queryset=model_queryset)\n    \nclass ObjectViewed(models.Model):\n    user                = models.ForeignKey(User, blank=True, null=True) # User instance instance.id\n    ip_address          = models.CharField(max_length=220, blank=True, null=True) #IP Field\n    content_type        = models.ForeignKey(ContentType) # User, Product, Order, Cart, Address\n    object_id           = models.PositiveIntegerField() # User id, Product id, Order id,\n    content_object      = GenericForeignKey('content_type', 'object_id') # Product instance\n    timestamp           = models.DateTimeField(auto_now_add=True)\n\n    objects = ObjectViewedManager()\n\n    def __str__(self):\n        return \"%s viewed on %s\" %(self.content_object, self.timestamp)\n\n    class Meta:\n        ordering = ['-timestamp'] # most recent saved show up first\n        verbose_name = 'Object viewed'\n        verbose_name_plural = 'Objects viewed'\n\n\ndef object_viewed_receiver(sender, instance, request, *args, **kwargs):\n    c_type = ContentType.objects.get_for_model(sender) # instance.__class__\n    user = None\n    if request.user.is_authenticated():\n        user = request.user\n    new_view_obj = ObjectViewed.objects.create(\n                user = user,\n                content_type=c_type,\n                object_id=instance.id,\n                ip_address = get_client_ip(request)\n        )\n\n\nobject_viewed_signal.connect(object_viewed_receiver)\n\n\n\n\n\nclass UserSession(models.Model):\n    user                = models.ForeignKey(User, blank=True, null=True) # User instance instance.id\n    ip_address          = models.CharField(max_length=220, blank=True, null=True) #IP Field\n    session_key         = models.CharField(max_length=100, blank=True, null=True) #min 50\n    timestamp           = models.DateTimeField(auto_now_add=True)\n    active              = models.BooleanField(default=True)\n    ended               = models.BooleanField(default=False)\n\n    def end_session(self):\n        session_key = self.session_key\n        ended = self.ended\n        try:\n            Session.objects.get(pk=session_key).delete()\n            self.active = False\n            self.ended = True\n            self.save()\n        except:\n            pass\n        return self.ended\n\n\n\ndef post_save_session_receiver(sender, instance, created, *args, **kwargs):\n    if created:\n        qs = UserSession.objects.filter(user=instance.user, ended=False, active=False).exclude(id=instance.id)\n        for i in qs:\n            i.end_session()\n    if not instance.active and not instance.ended:\n        instance.end_session()\n\nif FORCE_SESSION_TO_ONE:\n    post_save.connect(post_save_session_receiver, sender=UserSession)\n\n\ndef post_save_user_changed_receiver(sender, instance, created, *args, **kwargs):\n    if not created:\n        if instance.is_active == False:\n            qs = UserSession.objects.filter(user=instance.user, ended=False, active=False)\n            for i in qs:\n                i.end_session()\n\n\nif FORCE_INACTIVE_USER_ENDSESSION:\n    post_save.connect(post_save_user_changed_receiver, sender=User)\n\n\n\ndef user_logged_in_receiver(sender, instance, request, *args, **kwargs):\n    user = instance\n    ip_address = get_client_ip(request)\n    session_key = request.session.session_key # Django 1.11\n    UserSession.objects.create(\n            user=user,\n            ip_address=ip_address,\n            session_key=session_key\n        )\n\n\nuser_logged_in.connect(user_logged_in_receiver)\n\n\n\n"
  },
  {
    "path": "src/analytics/signals.py",
    "content": "from django.dispatch import Signal\n\n\nobject_viewed_signal = Signal(providing_args=['instance', 'request'])"
  },
  {
    "path": "src/analytics/templates/analytics/sales.html",
    "content": "{% extends \"base.html\" %}\n\n\n{% block content %}\n\n\n<div class='row my-5'>\n    <div class='col-12'>\n        <h1>Sales Data</h1>\n    </div>\n</div>\n\n<hr/>\n\n<div class='row my-5'>\n    <div class='col-4'>\n        <h3>Today's sales</h3>\n        <hr/>\n        <p>Recent Total: ${{ today.recent_data.total__sum }}</p>\n        <ul>\n        {% for order in today.recent|slice:\":5\" %}\n            <li class='my-3'>Order #{{ order.order_id }}<br/>\n            ${{ order.total }}<br/>\n            {{ order.updated|timesince }} ago</li>\n        {% endfor %}\n    </ul>\n   \n    <h3>This week's sales</h3>\n    <hr/>\n        <p>Recent Total: ${{ this_week.recent_data.total__sum }}</p>\n        <ul>\n        {% for order in this_week.recent|slice:\":5\" %}\n            <li class='my-3'>Order #{{ order.order_id }}<br/>\n            ${{ order.total }}<br/>\n            {{ order.updated|timesince }} ago</li>\n        {% endfor %}\n    </ul>\n    </div>\n\n    <div class='col'>\n       <canvas class='cfe-render-chart' id=\"thisWeekSales\" data-type='week' width=\"400\" height=\"400\"></canvas>\n    </div>\n</div>\n\n\n\n<hr/>\n\n<div class='row my-5'>\n    <div class='col-12'>\n        <h1>Previous 4 weeks</h1>\n    </div>\n    <div class='col'>\n        <p>Orders Total: ${{ last_four_weeks.recent_data.total__sum }}</p>\n        <p>Shipped Total: {% if last_four_weeks.shipped_data.total__sum %}${{ last_four_weeks.shipped_data.total__sum }} {% endif %}</p>\n        <p>Paid Totals: ${{ last_four_weeks.paid_data.total__sum }}</p>\n\n    </div>\n     <div class='col'>\n       <canvas class='cfe-render-chart' id=\"fourWeekSales\" data-type='4weeks' width=\"400\" height=\"400\"></canvas>\n    </div>\n</div>\n\n\n\n\n\n{% endblock %}"
  },
  {
    "path": "src/analytics/tests.py",
    "content": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "src/analytics/utils.py",
    "content": "\n\ndef get_client_ip(request):\n    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')\n    if x_forwarded_for:\n        ip = x_forwarded_for.split(\",\")[0]\n    else:\n        ip = request.META.get(\"REMOTE_ADDR\", None)\n    return ip"
  },
  {
    "path": "src/analytics/views.py",
    "content": "import random\nimport datetime\nfrom django.contrib.auth.mixins import LoginRequiredMixin\nfrom django.db.models import Count, Sum, Avg\nfrom django.http import HttpResponse, JsonResponse\nfrom django.views.generic import TemplateView, View\nfrom django.shortcuts import render\n\nfrom django.utils import  timezone\n\n\nfrom orders.models import Order\n\nclass SalesAjaxView(View):\n    def get(self, request, *args, **kwargs):\n        data = {}\n        if request.user.is_staff:\n            qs = Order.objects.all().by_weeks_range(weeks_ago=5, number_of_weeks=5)\n            if request.GET.get('type') == 'week':\n                days = 7\n                start_date = timezone.now().today() - datetime.timedelta(days=days-1)\n                datetime_list = []\n                labels = []\n                salesItems = []\n                for x in range(0, days):\n                    new_time = start_date + datetime.timedelta(days=x)\n                    datetime_list.append(\n                            new_time\n                        )\n                    labels.append(\n                        new_time.strftime(\"%a\") # mon\n                    )\n                    new_qs = qs.filter(updated__day=new_time.day, updated__month=new_time.month)\n                    day_total = new_qs.totals_data()['total__sum'] or 0\n                    salesItems.append(\n                        day_total\n                    )\n                #print(datetime_list)\n\n                data['labels'] = labels\n                data['data'] = salesItems\n            if request.GET.get('type') == '4weeks':\n                data['labels'] = [\"Four Weeks Ago\", \"Three Weeks Ago\", \"Two Weeks Ago\", \"Last Week\", \"This Week\"]\n                current = 5\n                data['data'] = []\n                for i in range(0, 5):\n                    new_qs = qs.by_weeks_range(weeks_ago=current, number_of_weeks=1)\n                    sales_total = new_qs.totals_data()['total__sum'] or 0\n                    data['data'].append(sales_total)\n                    current -= 1\n        return JsonResponse(data)\n\n\n\nclass SalesView(LoginRequiredMixin, TemplateView):\n    template_name = 'analytics/sales.html'\n\n    def dispatch(self, *args, **kwargs):\n        user = self.request.user\n        if not user.is_staff:\n            return render(self.request, \"400.html\", {})\n        return super(SalesView, self).dispatch(*args, **kwargs)\n\n\n    def get_context_data(self, *args, **kwargs):\n        context = super(SalesView, self).get_context_data(*args, **kwargs)\n        qs = Order.objects.all().by_weeks_range(weeks_ago=10, number_of_weeks=10)\n        start_date = timezone.now().date() - datetime.timedelta(hours=24)\n        end_date = timezone.now().date() + datetime.timedelta(hours=12)\n        today_data = qs.by_range(start_date=start_date, end_date=end_date).get_sales_breakdown()\n        context['today'] = today_data\n        context['this_week'] = qs.by_weeks_range(weeks_ago=1, number_of_weeks=1).get_sales_breakdown()\n        context['last_four_weeks'] = qs.by_weeks_range(weeks_ago=5, number_of_weeks=4).get_sales_breakdown()\n        return context"
  },
  {
    "path": "src/billing/__init__.py",
    "content": ""
  },
  {
    "path": "src/billing/admin.py",
    "content": "from django.contrib import admin\n\nfrom .models import BillingProfile, Card, Charge\n\nadmin.site.register(BillingProfile)\n\nadmin.site.register(Card)\n\nadmin.site.register(Charge)"
  },
  {
    "path": "src/billing/apps.py",
    "content": "from django.apps import AppConfig\n\n\nclass BillingConfig(AppConfig):\n    name = 'billing'\n"
  },
  {
    "path": "src/billing/migrations/0001_initial.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-28 20:50\nfrom __future__ import unicode_literals\n\nfrom django.conf import settings\nfrom django.db import migrations, models\nimport django.db.models.deletion\n\n\nclass Migration(migrations.Migration):\n\n    initial = True\n\n    dependencies = [\n        migrations.swappable_dependency(settings.AUTH_USER_MODEL),\n    ]\n\n    operations = [\n        migrations.CreateModel(\n            name='BillingProfile',\n            fields=[\n                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),\n                ('email', models.EmailField(max_length=254)),\n                ('active', models.BooleanField(default=True)),\n                ('update', models.DateTimeField(auto_now=True)),\n                ('timestamp', models.DateTimeField(auto_now_add=True)),\n                ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, unique=True)),\n            ],\n        ),\n    ]\n"
  },
  {
    "path": "src/billing/migrations/0002_auto_20170928_2052.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-28 20:52\nfrom __future__ import unicode_literals\n\nfrom django.conf import settings\nfrom django.db import migrations, models\nimport django.db.models.deletion\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('billing', '0001_initial'),\n    ]\n\n    operations = [\n        migrations.AlterField(\n            model_name='billingprofile',\n            name='user',\n            field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),\n        ),\n    ]\n"
  },
  {
    "path": "src/billing/migrations/0003_billingprofile_customer_id.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-11 19:13\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('billing', '0002_auto_20170928_2052'),\n    ]\n\n    operations = [\n        migrations.AddField(\n            model_name='billingprofile',\n            name='customer_id',\n            field=models.CharField(blank=True, max_length=120, null=True),\n        ),\n    ]\n"
  },
  {
    "path": "src/billing/migrations/0004_card.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-11 22:08\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\nimport django.db.models.deletion\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('billing', '0003_billingprofile_customer_id'),\n    ]\n\n    operations = [\n        migrations.CreateModel(\n            name='Card',\n            fields=[\n                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),\n                ('stripe_id', models.CharField(max_length=120)),\n                ('brand', models.CharField(blank=True, max_length=120, null=True)),\n                ('country', models.CharField(blank=True, max_length=20, null=True)),\n                ('exp_month', models.IntegerField(blank=True, null=True)),\n                ('exp_year', models.IntegerField(blank=True, null=True)),\n                ('last4', models.CharField(blank=True, max_length=4, null=True)),\n                ('billing_profile', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='billing.BillingProfile')),\n            ],\n        ),\n    ]\n"
  },
  {
    "path": "src/billing/migrations/0005_card_default.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-11 22:10\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('billing', '0004_card'),\n    ]\n\n    operations = [\n        migrations.AddField(\n            model_name='card',\n            name='default',\n            field=models.BooleanField(default=True),\n        ),\n    ]\n"
  },
  {
    "path": "src/billing/migrations/0006_charge.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-12 00:06\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\nimport django.db.models.deletion\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('billing', '0005_card_default'),\n    ]\n\n    operations = [\n        migrations.CreateModel(\n            name='Charge',\n            fields=[\n                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),\n                ('stripe_id', models.CharField(max_length=120)),\n                ('paid', models.BooleanField(default=False)),\n                ('refunded', models.BooleanField(default=False)),\n                ('outcome', models.TextField(blank=True, null=True)),\n                ('outcome_type', models.CharField(blank=True, max_length=120, null=True)),\n                ('seller_message', models.CharField(blank=True, max_length=120, null=True)),\n                ('risk_level', models.CharField(blank=True, max_length=120, null=True)),\n                ('billing_profile', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='billing.BillingProfile')),\n            ],\n        ),\n    ]\n"
  },
  {
    "path": "src/billing/migrations/0007_auto_20171012_1935.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-12 19:35\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\nimport django.utils.timezone\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('billing', '0006_charge'),\n    ]\n\n    operations = [\n        migrations.AddField(\n            model_name='card',\n            name='active',\n            field=models.BooleanField(default=True),\n        ),\n        migrations.AddField(\n            model_name='card',\n            name='timestamp',\n            field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),\n            preserve_default=False,\n        ),\n    ]\n"
  },
  {
    "path": "src/billing/migrations/__init__.py",
    "content": ""
  },
  {
    "path": "src/billing/models.py",
    "content": "from django.conf import settings\nfrom django.db import models\nfrom django.db.models.signals import post_save, pre_save\nfrom django.core.urlresolvers import reverse\nfrom accounts.models import GuestEmail\nUser = settings.AUTH_USER_MODEL\n\n# abc@teamcfe.com -->> 1000000 billing profiles\n# user abc@teamcfe.com -- 1 billing profile\n\nimport stripe\nSTRIPE_SECRET_KEY = getattr(settings, \"STRIPE_SECRET_KEY\", \"sk_test_cu1lQmcg1OLffhLvYrSCp5XE\")\nstripe.api_key = STRIPE_SECRET_KEY\n\n\n\nclass BillingProfileManager(models.Manager):\n    def new_or_get(self, request):\n        user = request.user\n        guest_email_id = request.session.get('guest_email_id')\n        created = False\n        obj = None\n        if user.is_authenticated():\n            'logged in user checkout; remember payment stuff'\n            obj, created = self.model.objects.get_or_create(\n                            user=user, email=user.email)\n        elif guest_email_id is not None:\n            'guest user checkout; auto reloads payment stuff'\n            guest_email_obj = GuestEmail.objects.get(id=guest_email_id)\n            obj, created = self.model.objects.get_or_create(\n                                            email=guest_email_obj.email)\n        else:\n            pass\n        return obj, created\n\nclass BillingProfile(models.Model):\n    user        = models.OneToOneField(User, null=True, blank=True)\n    email       = models.EmailField()\n    active      = models.BooleanField(default=True)\n    update      = models.DateTimeField(auto_now=True)\n    timestamp   = models.DateTimeField(auto_now_add=True)\n    customer_id = models.CharField(max_length=120, null=True, blank=True)\n    # customer_id in Stripe or Braintree\n\n    objects = BillingProfileManager()\n\n    def __str__(self):\n        return self.email\n\n    def charge(self, order_obj, card=None):\n        return Charge.objects.do(self, order_obj, card)\n\n    def get_cards(self):\n        return self.card_set.all()\n\n    def get_payment_method_url(self):\n        return reverse('billing-payment-method')\n\n    @property\n    def has_card(self): # instance.has_card\n        card_qs = self.get_cards()\n        return card_qs.exists() # True or False\n\n    @property\n    def default_card(self):\n        default_cards = self.get_cards().filter(active=True, default=True)\n        if default_cards.exists():\n            return default_cards.first()\n        return None\n\n    def set_cards_inactive(self):\n        cards_qs = self.get_cards()\n        cards_qs.update(active=False)\n        return cards_qs.filter(active=True).count()\n\ndef billing_profile_created_receiver(sender, instance, *args, **kwargs):\n    if not instance.customer_id and instance.email:\n        print(\"ACTUAL API REQUEST Send to stripe/braintree\")\n        customer = stripe.Customer.create(\n                email = instance.email\n            )\n        print(customer)\n        instance.customer_id = customer.id\n\npre_save.connect(billing_profile_created_receiver, sender=BillingProfile)\n\n\ndef user_created_receiver(sender, instance, created, *args, **kwargs):\n    if created and instance.email:\n        BillingProfile.objects.get_or_create(user=instance, email=instance.email)\n\npost_save.connect(user_created_receiver, sender=User)\n\n\nclass CardManager(models.Manager):\n    def all(self, *args, **kwargs): # ModelKlass.objects.all() --> ModelKlass.objects.filter(active=True)\n        return self.get_queryset().filter(active=True)\n\n    def add_new(self, billing_profile, token):\n        if token:\n            customer = stripe.Customer.retrieve(billing_profile.customer_id)\n            stripe_card_response = customer.sources.create(source=token)\n            new_card = self.model(\n                    billing_profile=billing_profile,\n                    stripe_id = stripe_card_response.id,\n                    brand = stripe_card_response.brand,\n                    country = stripe_card_response.country,\n                    exp_month = stripe_card_response.exp_month,\n                    exp_year = stripe_card_response.exp_year,\n                    last4 = stripe_card_response.last4\n                )\n            new_card.save()\n            return new_card\n        return None\n\n\nclass Card(models.Model):\n    billing_profile         = models.ForeignKey(BillingProfile)\n    stripe_id               = models.CharField(max_length=120)\n    brand                   = models.CharField(max_length=120, null=True, blank=True)\n    country                 = models.CharField(max_length=20, null=True, blank=True)\n    exp_month               = models.IntegerField(null=True, blank=True)\n    exp_year                = models.IntegerField(null=True, blank=True)\n    last4                   = models.CharField(max_length=4, null=True, blank=True)\n    default                 = models.BooleanField(default=True)\n    active                  = models.BooleanField(default=True)\n    timestamp               = models.DateTimeField(auto_now_add=True)\n\n    objects = CardManager()\n\n    def __str__(self):\n        return \"{} {}\".format(self.brand, self.last4)\n\n\ndef new_card_post_save_receiver(sender, instance, created, *args, **kwargs):\n    if instance.default:\n        billing_profile = instance.billing_profile\n        qs = Card.objects.filter(billing_profile=billing_profile).exclude(pk=instance.pk)\n        qs.update(default=False)\n\n\npost_save.connect(new_card_post_save_receiver, sender=Card)\n\n\n\n# stripe.Charge.create(\n#   amount = int(order_obj.total * 100),\n#   currency = \"usd\",\n#   customer =  BillingProfile.objects.filter(email='hello@teamcfe.com').first().stripe_id,\n#   source = Card.objects.filter(billing_profile__email='hello@teamcfe.com').first().stripe_id, # obtained with Stripe.js\n#   description=\"Charge for elijah.martin@example.com\"\n# )\n\nclass ChargeManager(models.Manager):\n    def do(self, billing_profile, order_obj, card=None): # Charge.objects.do()\n        card_obj = card\n        if card_obj is None:\n            cards = billing_profile.card_set.filter(default=True) # card_obj.billing_profile\n            if cards.exists():\n                card_obj = cards.first()\n        if card_obj is None:\n            return False, \"No cards available\"\n        c = stripe.Charge.create(\n              amount = int(order_obj.total * 100), # 39.19 --> 3919\n              currency = \"usd\",\n              customer =  billing_profile.customer_id,\n              source = card_obj.stripe_id,\n              metadata={\"order_id\":order_obj.order_id},\n            )\n        new_charge_obj = self.model(\n                billing_profile = billing_profile,\n                stripe_id = c.id,\n                paid = c.paid,\n                refunded = c.refunded,\n                outcome = c.outcome,\n                outcome_type = c.outcome['type'],\n                seller_message = c.outcome.get('seller_message'),\n                risk_level = c.outcome.get('risk_level'),\n        )\n        new_charge_obj.save()\n        return new_charge_obj.paid, new_charge_obj.seller_message\n\n\nclass Charge(models.Model):\n    billing_profile         = models.ForeignKey(BillingProfile)\n    stripe_id               = models.CharField(max_length=120)\n    paid                    = models.BooleanField(default=False)\n    refunded                = models.BooleanField(default=False)\n    outcome                 = models.TextField(null=True, blank=True)\n    outcome_type            = models.CharField(max_length=120, null=True, blank=True)\n    seller_message          = models.CharField(max_length=120, null=True, blank=True)\n    risk_level              = models.CharField(max_length=120, null=True, blank=True)\n\n    objects = ChargeManager()\n\n\n\n"
  },
  {
    "path": "src/billing/templates/billing/payment-method.html",
    "content": "{% extends 'base.html' %}\n\n\n{% block content %}\n\n<div class='col-10 col-md-6 mx-auto'>\n    <h1>Add Payment Method</h1>\n    <div class='stripe-payment-form' data-token='{{ publish_key }}' data-next-url='{% if next_url %}{{ next_url }}{% endif %}' data-btn-title='Add New Card'></div>\n</div>\n\n\n{% endblock %}\n"
  },
  {
    "path": "src/billing/tests.py",
    "content": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "src/billing/views.py",
    "content": "from django.conf import settings\nfrom django.http import JsonResponse, HttpResponse\nfrom django.shortcuts import render, redirect\nfrom django.utils.http import is_safe_url\n\n\n\n\nimport stripe\nSTRIPE_SECRET_KEY = getattr(settings, \"STRIPE_SECRET_KEY\", \"sk_test_cu1lQmcg1OLffhLvYrSCp5XE\")\nSTRIPE_PUB_KEY =  getattr(settings, \"STRIPE_PUB_KEY\", 'pk_test_PrV61avxnHaWIYZEeiYTTVMZ')\nstripe.api_key = STRIPE_SECRET_KEY\n\n\n\nfrom .models import BillingProfile, Card\n\ndef payment_method_view(request):\n    #next_url = \n    # if request.user.is_authenticated():\n    #     billing_profile = request.user.billingprofile\n    #     my_customer_id = billing_profile.customer_id\n\n    billing_profile, billing_profile_created = BillingProfile.objects.new_or_get(request)\n    if not billing_profile:\n        return redirect(\"/cart\")\n    next_url = None\n    next_ = request.GET.get('next')\n    if is_safe_url(next_, request.get_host()):\n        next_url = next_\n    return render(request, 'billing/payment-method.html', {\"publish_key\": STRIPE_PUB_KEY, \"next_url\": next_url})\n\n\n\n\ndef payment_method_createview(request):\n    if request.method == \"POST\" and request.is_ajax():\n        billing_profile, billing_profile_created = BillingProfile.objects.new_or_get(request)\n        if not billing_profile:\n            return HttpResponse({\"message\": \"Cannot find this user\"}, status_code=401)\n        token = request.POST.get(\"token\")\n        if token is not None:\n            new_card_obj = Card.objects.add_new(billing_profile, token)\n        return JsonResponse({\"message\": \"Success! Your card was added.\"})\n    return HttpResponse(\"error\", status_code=401)\n\n\n\n\n"
  },
  {
    "path": "src/carts/__init__.py",
    "content": ""
  },
  {
    "path": "src/carts/admin.py",
    "content": "from django.contrib import admin\n\n\nfrom .models import Cart\n\nadmin.site.register(Cart)"
  },
  {
    "path": "src/carts/apps.py",
    "content": "from django.apps import AppConfig\n\n\nclass CartsConfig(AppConfig):\n    name = 'carts'\n"
  },
  {
    "path": "src/carts/migrations/0001_initial.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-26 00:27\nfrom __future__ import unicode_literals\n\nfrom django.conf import settings\nfrom django.db import migrations, models\nimport django.db.models.deletion\n\n\nclass Migration(migrations.Migration):\n\n    initial = True\n\n    dependencies = [\n        ('products', '0009_product_timestamp'),\n        migrations.swappable_dependency(settings.AUTH_USER_MODEL),\n    ]\n\n    operations = [\n        migrations.CreateModel(\n            name='Cart',\n            fields=[\n                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),\n                ('total', models.DecimalField(decimal_places=2, default=0.0, max_digits=100)),\n                ('updated', models.DateTimeField(auto_now=True)),\n                ('timestamp', models.DateTimeField(auto_now_add=True)),\n                ('products', models.ManyToManyField(blank=True, to='products.Product')),\n                ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),\n            ],\n        ),\n    ]\n"
  },
  {
    "path": "src/carts/migrations/0002_cart_subtotal.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-26 01:23\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('carts', '0001_initial'),\n    ]\n\n    operations = [\n        migrations.AddField(\n            model_name='cart',\n            name='subtotal',\n            field=models.DecimalField(decimal_places=2, default=0.0, max_digits=100),\n        ),\n    ]\n"
  },
  {
    "path": "src/carts/migrations/__init__.py",
    "content": ""
  },
  {
    "path": "src/carts/models.py",
    "content": "from decimal import Decimal\nfrom django.conf import settings\nfrom django.db import models\nfrom django.db.models.signals import pre_save, post_save, m2m_changed\n\nfrom products.models import Product\n\n\nUser = settings.AUTH_USER_MODEL\n\nclass CartManager(models.Manager):\n    def new_or_get(self, request):\n        cart_id = request.session.get(\"cart_id\", None)\n        qs = self.get_queryset().filter(id=cart_id)\n        if qs.count() == 1:\n            new_obj = False\n            cart_obj = qs.first()\n            if request.user.is_authenticated() and cart_obj.user is None:\n                cart_obj.user = request.user\n                cart_obj.save()\n        else:\n            cart_obj = Cart.objects.new(user=request.user)\n            new_obj = True\n            request.session['cart_id'] = cart_obj.id\n        return cart_obj, new_obj\n\n    def new(self, user=None):\n        user_obj = None\n        if user is not None:\n            if user.is_authenticated():\n                user_obj = user\n        return self.model.objects.create(user=user_obj)\n\nclass Cart(models.Model):\n    user        = models.ForeignKey(User, null=True, blank=True)\n    products    = models.ManyToManyField(Product, blank=True)\n    subtotal    = models.DecimalField(default=0.00, max_digits=100, decimal_places=2)\n    total       = models.DecimalField(default=0.00, max_digits=100, decimal_places=2)\n    updated     = models.DateTimeField(auto_now=True)\n    timestamp   = models.DateTimeField(auto_now_add=True)\n\n    objects = CartManager()\n\n    def __str__(self):\n        return str(self.id)\n\n    @property\n    def is_digital(self):\n        qs = self.products.all() #every product\n        new_qs = qs.filter(is_digital=False) # every product that is not digial\n        if new_qs.exists():\n            return False\n        return True\n\n\n\n\ndef m2m_changed_cart_receiver(sender, instance, action, *args, **kwargs):\n    if action == 'post_add' or action == 'post_remove' or action == 'post_clear':\n        products = instance.products.all()\n        total = 0\n        for x in products:\n            total += x.price\n        if instance.subtotal != total:\n            instance.subtotal = total\n            instance.save()\n\nm2m_changed.connect(m2m_changed_cart_receiver, sender=Cart.products.through)\n\n\n\n\ndef pre_save_cart_receiver(sender, instance, *args, **kwargs):\n    if instance.subtotal > 0:\n        instance.total = Decimal(instance.subtotal) * Decimal(1.08) # 8% tax\n    else:\n        instance.total = 0.00\n\npre_save.connect(pre_save_cart_receiver, sender=Cart)\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "src/carts/templates/carts/checkout-done.html",
    "content": "{% extends \"base.html\" %}\n\n\n{% block content %}\n<div class='col-6 mx-auto py-5 text-center'>\n  <h1 class='display-1'>Thank you for your order!!!</h1>\n</div>\n\n{% endblock %}"
  },
  {
    "path": "src/carts/templates/carts/checkout.html",
    "content": "{% extends \"base.html\" %}\n\n\n{% block content %}\n{% if not billing_profile %}\n    <div class='row text-center'>\n    <div class='col-12 col-md-6'>\n        <p class='lead'>Login</p>\n        {% include 'accounts/snippets/form.html' with form=login_form next_url=request.build_absolute_uri %}\n    </div>\n    <div class='col-12 col-md-6'> \n        Continue as Guest\n\n        {% url \"guest_register\" as guest_register_url %}\n        {% include 'accounts/snippets/form.html' with form=guest_form next_url=request.build_absolute_uri action_url=guest_register_url %}\n    </div>\n\n    </div>\n\n{% else %}\n            \n        {% if not object.shipping_address and shipping_address_required %}\n\n         <div class='row'>\n            <div class='col-12'>\n                <p class='lead'>Shipping Address</p>\n                <hr/>\n            </div>\n            <div class='col-6'>\n                \n\n           \n\n                    {% url \"checkout_address_create\" as checkout_address_create %}\n                    {% include 'addresses/form.html' with form=address_form next_url=request.build_absolute_uri action_url=checkout_address_create address_type='shipping' %}'\n\n\n\n             </div>\n         <div class='col-6'>\n            {% url 'checkout_address_reuse' as checkout_address_reuse %}\n            {% include 'addresses/prev_addresses.html' with address_qs=address_qs next_url=request.build_absolute_uri address_type='shipping' action_url=checkout_address_reuse %}\n            </div>\n        </div>\n\n\n        {% elif not object.billing_address %}\n        <div class='row'>\n            <div class='col-12'>\n                 <p class='lead'>Billing Address</p>\n                <hr/>\n            </div>\n            <div class='col-6'>\n               \n            {% url \"checkout_address_create\" as checkout_address_create %}\n            {% include 'addresses/form.html' with form=address_form next_url=request.build_absolute_uri action_url=checkout_address_create address_type='billing' %}\n            </div>\n              <div class='col-6'>\n                {% url 'checkout_address_reuse' as checkout_address_reuse %}\n             {% include 'addresses/prev_addresses.html' with address_qs=address_qs next_url=request.build_absolute_uri  address_type='billing' action_url=checkout_address_reuse %}\n         </div>\n\n         \n        </div>\n        {% else %}\n            {% if not has_card %}\n                <!-- enter credit card here -->\n                <div class='stripe-payment-form' data-token='{{ publish_key }}' data-next-url='{{ request.build_absolute_uri }}' data-btn-title='Add Payment Method'></div>\n\n            {% else %}\n                <h1>Finalize Checkout</h1>\n                <p>Cart Items: {% for product in object.cart.products.all %}{{ product }}{% if not forloop.last %}, {% endif %}{% endfor %}</p>\n                <p>Shipping Address: {{ object.shipping_address_final }}</p>\n                <p>Billing Address: {{ object.billing_address_final }}</p>\n                <p>Payment Method: {{ billing_profile.default_card }} (<a href=\"{{ billing_profile.get_payment_method_url }}?next={{ request.build_absolute_uri }}\">Change</a>)</p>\n                <p>Cart Total: {{ object.cart.total }}</p>\n                <p>Shipping Total: {{ object.shipping_total }}</p>\n                <p>Order Total: {{ object.total }}</p>\n\n                <form class='form' method='POST' action=\"\">{% csrf_token %}\n                    <button type='submit' class='btn btn-success'>Checkout</button>\n                </form>\n            {% endif %}\n        {% endif %}\n{% endif %}\n\n\n\n{% endblock %}"
  },
  {
    "path": "src/carts/templates/carts/home.html",
    "content": "{% extends \"base.html\" %}\n\n\n{% block content %}\n<h1>Cart</h1>\n\n{% if cart.products.exists %}\n<table class=\"table cart-table\">\n  <thead>\n    <tr>\n      <th>#</th>\n      <th>Product Name</th>\n      <th>Product Price</th>\n    </tr>\n  </thead>\n  <tbody class='cart-body'>\n    {% for product in cart.products.all %}\n    <tr class='cart-product'>\n      <th scope=\"row\">{{ forloop.counter }}</th>\n      <td><a href='{{ product.get_absolute_url }}'>{{ product.title }}</a> \n        {% include 'carts/snippets/remove-product.html' with product_id=product.id %}\n      </td>\n      <td>{{ product.price }}</td>\n    </tr>\n    {% endfor %}\n    <tr>\n      <td colspan=\"2\"></td>\n      <td><b>Subtotal</b> $<span class='cart-subtotal'>{{ cart.subtotal }}</span></td>\n    </tr>\n    <tr>\n      <td colspan=\"2\"></td>\n      <td><b>Total</b> $<span class='cart-total'>{{ cart.total }}</span></td>\n    </tr>\n    <tr>\n      <td colspan=\"2\"></td>\n      <td><a class='btn btn-lg btn-success' href='{% url \"cart:checkout\" %}'>Checkout</a></td>\n    </tr>\n\n  </tbody>\n</table>\n\n<div class='cart-item-remove-form' style='display:none'>\n\n    {% include 'carts/snippets/remove-product.html' %}\n  </div>\n\n{% else %}\n<p class='lead'>Cart is empty</p>\n{% endif %}\n\n\n{% endblock %}"
  },
  {
    "path": "src/carts/templates/carts/snippets/remove-product.html",
    "content": "<form class='form-product-ajax' method='POST' action='{% url \"cart:update\" %}' data-endpoint='{% url \"cart:update\" %}' class=\"form\"> {% csrf_token %}\n    <input class='cart-item-product-id' type='hidden' name='product_id' value='{{ product_id }}' />\n      <button type='submit' class='btn btn-link btn-sm' style=\"padding:0px;cursor: pointer;\">Remove?</button>\n    </span>\n</form>"
  },
  {
    "path": "src/carts/tests.py",
    "content": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "src/carts/urls.py",
    "content": "from django.conf.urls import url\n\nfrom .views import (\n        cart_home, \n        cart_update, \n        checkout_home,\n        checkout_done_view\n        )\n\nurlpatterns = [\n    url(r'^$', cart_home, name='home'),\n    url(r'^checkout/success/$', checkout_done_view, name='success'),\n    url(r'^checkout/$', checkout_home, name='checkout'),\n    url(r'^update/$', cart_update, name='update'),\n]"
  },
  {
    "path": "src/carts/views.py",
    "content": "from django.conf import settings\nfrom django.http import JsonResponse\nfrom django.shortcuts import render, redirect\n\n\nfrom accounts.forms import LoginForm, GuestForm\nfrom accounts.models import GuestEmail\n\nfrom addresses.forms import AddressCheckoutForm\nfrom addresses.models import Address\n\nfrom billing.models import BillingProfile\nfrom orders.models import Order\nfrom products.models import Product\nfrom .models import Cart\n\n\nimport stripe\nSTRIPE_SECRET_KEY = getattr(settings, \"STRIPE_SECRET_KEY\", \"sk_test_cu1lQmcg1OLffhLvYrSCp5XE\")\nSTRIPE_PUB_KEY =  getattr(settings, \"STRIPE_PUB_KEY\", 'pk_test_PrV61avxnHaWIYZEeiYTTVMZ')\nstripe.api_key = STRIPE_SECRET_KEY\n\n\n\ndef cart_detail_api_view(request):\n    cart_obj, new_obj = Cart.objects.new_or_get(request)\n    products = [{\n            \"id\": x.id,\n            \"url\": x.get_absolute_url(),\n            \"name\": x.name, \n            \"price\": x.price\n            } \n            for x in cart_obj.products.all()]\n    cart_data  = {\"products\": products, \"subtotal\": cart_obj.subtotal, \"total\": cart_obj.total}\n    return JsonResponse(cart_data)\n\ndef cart_home(request):\n    cart_obj, new_obj = Cart.objects.new_or_get(request)\n    return render(request, \"carts/home.html\", {\"cart\": cart_obj})\n\n\ndef cart_update(request):\n    product_id = request.POST.get('product_id')\n    \n    if product_id is not None:\n        try:\n            product_obj = Product.objects.get(id=product_id)\n        except Product.DoesNotExist:\n            print(\"Show message to user, product is gone?\")\n            return redirect(\"cart:home\")\n        cart_obj, new_obj = Cart.objects.new_or_get(request)\n        if product_obj in cart_obj.products.all():\n            cart_obj.products.remove(product_obj)\n            added = False\n        else:\n            cart_obj.products.add(product_obj) # cart_obj.products.add(product_id)\n            added = True\n        request.session['cart_items'] = cart_obj.products.count()\n        # return redirect(product_obj.get_absolute_url())\n        if request.is_ajax(): # Asynchronous JavaScript And XML / JSON\n            print(\"Ajax request\")\n            json_data = {\n                \"added\": added,\n                \"removed\": not added,\n                \"cartItemCount\": cart_obj.products.count()\n            }\n            return JsonResponse(json_data, status=200) # HttpResponse\n            # return JsonResponse({\"message\": \"Error 400\"}, status=400) # Django Rest Framework\n    return redirect(\"cart:home\")\n\n\n\ndef checkout_home(request):\n    cart_obj, cart_created = Cart.objects.new_or_get(request)\n    order_obj = None\n    if cart_created or cart_obj.products.count() == 0:\n        return redirect(\"cart:home\")  \n    \n    login_form = LoginForm(request=request)\n    guest_form = GuestForm(request=request)\n    address_form = AddressCheckoutForm()\n    billing_address_id = request.session.get(\"billing_address_id\", None)\n\n    shipping_address_required = not cart_obj.is_digital\n\n\n    shipping_address_id = request.session.get(\"shipping_address_id\", None)\n\n    billing_profile, billing_profile_created = BillingProfile.objects.new_or_get(request)\n    address_qs = None\n    has_card = False\n    if billing_profile is not None:\n        if request.user.is_authenticated():\n            address_qs = Address.objects.filter(billing_profile=billing_profile)\n        order_obj, order_obj_created = Order.objects.new_or_get(billing_profile, cart_obj)\n        if shipping_address_id:\n            order_obj.shipping_address = Address.objects.get(id=shipping_address_id)\n            del request.session[\"shipping_address_id\"]\n        if billing_address_id:\n            order_obj.billing_address = Address.objects.get(id=billing_address_id) \n            del request.session[\"billing_address_id\"]\n        if billing_address_id or shipping_address_id:\n            order_obj.save()\n        has_card = billing_profile.has_card\n\n    if request.method == \"POST\":\n        \"check that order is done\"\n        is_prepared = order_obj.check_done()\n        if is_prepared:\n            did_charge, crg_msg = billing_profile.charge(order_obj)\n            if did_charge:\n                order_obj.mark_paid() # sort a signal for us\n                request.session['cart_items'] = 0\n                del request.session['cart_id']\n                if not billing_profile.user:\n                    '''\n                    is this the best spot?\n                    '''\n                    billing_profile.set_cards_inactive()\n                return redirect(\"cart:success\")\n            else:\n                print(crg_msg)\n                return redirect(\"cart:checkout\")\n    context = {\n        \"object\": order_obj,\n        \"billing_profile\": billing_profile,\n        \"login_form\": login_form,\n        \"guest_form\": guest_form,\n        \"address_form\": address_form,\n        \"address_qs\": address_qs,\n        \"has_card\": has_card,\n        \"publish_key\": STRIPE_PUB_KEY,\n        \"shipping_address_required\": shipping_address_required,\n    }\n    return render(request, \"carts/checkout.html\", context)\n\n\n\n\n\n\n\ndef checkout_done_view(request):\n    return render(request, \"carts/checkout-done.html\", {})\n\n\n\n\n\n\n"
  },
  {
    "path": "src/ecommerce/__init__.py",
    "content": ""
  },
  {
    "path": "src/ecommerce/aws/__init__.py",
    "content": ""
  },
  {
    "path": "src/ecommerce/aws/conf.py",
    "content": "import datetime\nimport os\n\ntry:\n    from .ignore2 import AWS_ACCESS_KEY_ID,  AWS_SECRET_ACCESS_KEY\nexcept:\n    AWS_ACCESS_KEY_ID = os.environ.get(\"AWS_ACCESS_KEY_ID\", \"AKIAJARK375PALZJC55Q\")\n    AWS_SECRET_ACCESS_KEY = os.environ.get(\"AWS_SECRET_ACCESS_KEY\", \"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\")\n\nAWS_GROUP_NAME = \"CFE_eCommerce_Group\"\nAWS_USERNAME = \"cfe-ecommerce-user\"\n\nAWS_FILE_EXPIRE = 200\nAWS_PRELOAD_METADATA = True\nAWS_QUERYSTRING_AUTH = False\n\nDEFAULT_FILE_STORAGE = 'ecommerce.aws.utils.MediaRootS3BotoStorage'\nSTATICFILES_STORAGE = 'ecommerce.aws.utils.StaticRootS3BotoStorage'\nAWS_STORAGE_BUCKET_NAME = 'cfe-ecommerce'\nS3DIRECT_REGION = 'us-west-2'\nS3_URL = '//%s.s3.amazonaws.com/' % AWS_STORAGE_BUCKET_NAME\nMEDIA_URL = '//%s.s3.amazonaws.com/media/' % AWS_STORAGE_BUCKET_NAME\nMEDIA_ROOT = MEDIA_URL\nSTATIC_URL = S3_URL + 'static/'\nADMIN_MEDIA_PREFIX = STATIC_URL + 'admin/'\n\ntwo_months = datetime.timedelta(days=61)\ndate_two_months_later = datetime.date.today() + two_months\nexpires = date_two_months_later.strftime(\"%A, %d %B %Y 20:00:00 GMT\")\n\nAWS_HEADERS = { \n 'Expires': expires,\n 'Cache-Control': 'max-age=%d' % (int(two_months.total_seconds()), ),\n}\n\nPROTECTED_DIR_NAME = 'protected'\nPROTECTED_MEDIA_URL = '//%s.s3.amazonaws.com/%s/' %( AWS_STORAGE_BUCKET_NAME, PROTECTED_DIR_NAME)\n\nAWS_DOWNLOAD_EXPIRE = 5000 #(0ptional, in milliseconds)\n\n\n\n"
  },
  {
    "path": "src/ecommerce/aws/download/__init__.py",
    "content": ""
  },
  {
    "path": "src/ecommerce/aws/download/utils.py",
    "content": "import boto\nimport re\nimport os\n\nfrom django.conf import settings\nfrom boto.s3.connection import OrdinaryCallingFormat\n\n\nclass AWSDownload(object):\n    access_key = None\n    secret_key = None\n    bucket = None\n    region = None\n    expires = getattr(settings, 'AWS_DOWNLOAD_EXPIRE', 5000)\n\n    def __init__(self,  access_key, secret_key, bucket, region, *args, **kwargs):\n        self.bucket = bucket\n        self.access_key = access_key\n        self.secret_key = secret_key\n        self.region = region\n        super(AWSDownload, self).__init__(*args, **kwargs)\n\n    def s3connect(self):\n        conn = boto.s3.connect_to_region(\n                self.region,\n                aws_access_key_id=self.access_key, \n                aws_secret_access_key=self.secret_key,\n                is_secure=True,\n                calling_format=OrdinaryCallingFormat()\n            )\n        return conn\n\n    def get_bucket(self):\n        conn = self.s3connect()\n        bucket_name = self.bucket\n        bucket = conn.get_bucket(bucket_name)\n        return bucket\n\n    def get_key(self, path):\n        bucket = self.get_bucket()\n        key = bucket.get_key(path)\n        return key\n\n    def get_filename(self, path, new_filename=None):\n        current_filename =  os.path.basename(path)\n        if new_filename is not None:\n            filename, file_extension = os.path.splitext(current_filename)\n            escaped_new_filename_base = re.sub(\n                                            '[^A-Za-z0-9\\#]+', \n                                            '-', \n                                            new_filename)\n            escaped_filename = escaped_new_filename_base + file_extension\n            return escaped_filename\n        return current_filename\n\n    def generate_url(self, path, download=True, new_filename=None):\n        file_url = None\n        aws_obj_key = self.get_key(path)\n        if aws_obj_key:\n            headers = None\n            if download:\n                filename = self.get_filename(path, new_filename=new_filename)\n                headers = {\n                    'response-content-type': 'application/force-download',\n                    'response-content-disposition':'attachment;filename=\"%s\"'%filename\n                }\n            file_url = aws_obj_key.generate_url(\n                                response_headers=headers,\n                                 expires_in=self.expires, \n                                method='GET') \n        return file_url"
  },
  {
    "path": "src/ecommerce/aws/utils.py",
    "content": "from storages.backends.s3boto3 import S3Boto3Storage\n\nStaticRootS3BotoStorage = lambda: S3Boto3Storage(location='static')\nMediaRootS3BotoStorage  = lambda: S3Boto3Storage(location='media')\nProtectedS3Storage  = lambda: S3Boto3Storage(location='protected')"
  },
  {
    "path": "src/ecommerce/forms.py",
    "content": "from django import forms\nfrom django.contrib.auth import get_user_model\n\nUser = get_user_model()\n\nclass ContactForm(forms.Form):\n    fullname = forms.CharField(\n            widget=forms.TextInput(\n                    attrs={\n                        \"class\": \"form-control\", \n                        \"placeholder\": \"Your full name\"\n                    }\n                    )\n            )\n    email    = forms.EmailField(\n            widget=forms.EmailInput(\n                    attrs={\n                        \"class\": \"form-control\", \n                        \"placeholder\": \"Your email\"\n                    }\n                    )\n            )\n    content  = forms.CharField(\n            widget=forms.Textarea(\n                attrs={\n                    'class': 'form-control',\n                    \"placeholder\": \"Your message\" \n                    }\n                )\n            )\n\n    # def clean_email(self):\n    #     email = self.cleaned_data.get(\"email\")\n    #     if not \"gmail.com\" in email:\n    #         raise forms.ValidationError(\"Email has to be gmail.com\")\n    #     return email\n\n    # def clean_content(self):\n    #     raise forms.ValidationError(\"Content is wrong.\")\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "src/ecommerce/mixins.py",
    "content": "from django.utils.http import is_safe_url\n\n\nclass RequestFormAttachMixin(object):\n    def get_form_kwargs(self):\n        kwargs = super(RequestFormAttachMixin, self).get_form_kwargs()\n        kwargs['request'] = self.request\n        return kwargs\n\n\nclass NextUrlMixin(object):\n    default_next = \"/\"\n    def get_next_url(self):\n        request = self.request\n        next_ = request.GET.get('next')\n        next_post = request.POST.get('next')\n        redirect_path = next_ or next_post or None\n        if is_safe_url(redirect_path, request.get_host()):\n                return redirect_path\n        return self.default_next"
  },
  {
    "path": "src/ecommerce/settings/__init__.py",
    "content": "from .base import *\n\nfrom .production import *\n\ntry:\n    from .local import *\nexcept:\n    pass\n\ntry:\n    from .local_justin import *\nexcept:\n    pass"
  },
  {
    "path": "src/ecommerce/settings/base.py",
    "content": "\"\"\"\nDjango settings for ecommerce project.\n\nGenerated by 'django-admin startproject' using Django 1.11.4.\n\nFor more information on this file, see\nhttps://docs.djangoproject.com/en/1.11/topics/settings/\n\nFor the full list of settings and their values, see\nhttps://docs.djangoproject.com/en/1.11/ref/settings/\n\"\"\"\n\nimport os\n\n# Build paths inside the project like this: os.path.join(BASE_DIR, ...)\nBASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))\n\n\n# Quick-start development settings - unsuitable for production\n# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/\n\n# SECURITY WARNING: keep the secret key used in production secret!\nSECRET_KEY = '@!-)jwmuzh8btr380g61=g+#&zzei&dz2(&=xbvxztady)_p(r'\n\n# SECURITY WARNING: don't run with debug turned on in production!\nDEBUG = True\n\nALLOWED_HOSTS = []\n\nEMAIL_HOST = 'smtp.gmail.com'\nEMAIL_HOST_USER = 'hungrypy@gmail.com' \nEMAIL_HOST_PASSWORD = 'yourpassword'\nEMAIL_PORT = 587\nEMAIL_USE_TLS = True\nDEFAULT_FROM_EMAIL = 'Python ecommerce <hungrypy@gmail.com>'\nBASE_URL = '127.0.0.1:8000'\n\n\nMANAGERS = (\n    ('Justin Mitchel', \"hungrypy@gmail.com\"),\n)\n\nADMINS = MANAGERS\n\n\n\n# Application definition\n\nINSTALLED_APPS = [\n    'django.contrib.admin',\n    'django.contrib.auth',\n    'django.contrib.contenttypes',\n    'django.contrib.sessions',\n    'django.contrib.messages',\n    'django.contrib.staticfiles',\n    # third party\n    'storages',\n\n    #our apps\n    'accounts',\n    'addresses',\n    'analytics',\n    'billing',\n    'carts',\n    'marketing',\n    'orders',\n    'products',\n    'search',\n    'tags',\n]\n\nAUTH_USER_MODEL = 'accounts.User' #changes the built-in user model to ours\nLOGIN_URL = '/login/'\nLOGIN_URL_REDIRECT = '/'\nLOGOUT_URL = '/logout/'\n\nFORCE_SESSION_TO_ONE = False\nFORCE_INACTIVE_USER_ENDSESSION= False\n\n\n\nMAILCHIMP_API_KEY = \"717d0854ed20fed3be3689a3f125915c-us17\"\nMAILCHIMP_DATA_CENTER = \"us17\"\nMAILCHIMP_EMAIL_LIST_ID = \"e2ef12efee\"\n\n\nSTRIPE_SECRET_KEY = \"sk_test_cu1lQmcg1OLffhLvYrSCp5XE\"\nSTRIPE_PUB_KEY = 'pk_test_PrV61avxnHaWIYZEeiYTTVMZ'\n\n\nMIDDLEWARE = [\n    'django.middleware.security.SecurityMiddleware',\n    'django.contrib.sessions.middleware.SessionMiddleware',\n    'django.middleware.common.CommonMiddleware',\n    'django.middleware.csrf.CsrfViewMiddleware',\n    'django.contrib.auth.middleware.AuthenticationMiddleware',\n    'django.contrib.messages.middleware.MessageMiddleware',\n    'django.middleware.clickjacking.XFrameOptionsMiddleware',\n]\n\nLOGOUT_REDIRECT_URL = '/login/'\nROOT_URLCONF = 'ecommerce.urls'\n\nTEMPLATES = [\n    {\n        'BACKEND': 'django.template.backends.django.DjangoTemplates',\n        'DIRS': [os.path.join(BASE_DIR, 'templates')],\n        'APP_DIRS': True,\n        'OPTIONS': {\n            'context_processors': [\n                'django.template.context_processors.debug',\n                'django.template.context_processors.request',\n                'django.contrib.auth.context_processors.auth',\n                'django.contrib.messages.context_processors.messages',\n            ],\n        },\n    },\n]\n\nWSGI_APPLICATION = 'ecommerce.wsgi.application'\n\n\n# Database\n# https://docs.djangoproject.com/en/1.11/ref/settings/#databases\n\nDATABASES = {\n    'default': {\n        'ENGINE': 'django.db.backends.sqlite3',\n        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),\n    }\n}\n\n\n# Password validation\n# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators\n\nAUTH_PASSWORD_VALIDATORS = [\n    {\n        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',\n    },\n]\n\n\n# Internationalization\n# https://docs.djangoproject.com/en/1.11/topics/i18n/\n\nLANGUAGE_CODE = 'en-us'\n\nTIME_ZONE = 'UTC'\n\nUSE_I18N = True\n\nUSE_L10N = True\n\nUSE_TZ = True\n\n\n# Static files (CSS, JavaScript, Images)\n# https://docs.djangoproject.com/en/1.11/howto/static-files/\n\nSTATIC_URL = '/static/'\n\nSTATICFILES_DIRS = [\n    os.path.join(BASE_DIR, \"static_my_proj\"),\n]\n\nSTATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), \"static_cdn\", \"static_root\")\n\n\nMEDIA_URL = '/media/'\nMEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR), \"static_cdn\", \"media_root\")\n\n\nPROTECTED_ROOT = os.path.join(os.path.dirname(BASE_DIR), \"static_cdn\", \"protected_media\")\n\n\n\nfrom ecommerce.aws.conf import *\n\n\nCORS_REPLACE_HTTPS_REFERER      = False\nHOST_SCHEME                     = \"http://\"\nSECURE_PROXY_SSL_HEADER         = None\nSECURE_SSL_REDIRECT             = False\nSESSION_COOKIE_SECURE           = False\nCSRF_COOKIE_SECURE              = False\nSECURE_HSTS_SECONDS             = None\nSECURE_HSTS_INCLUDE_SUBDOMAINS  = False\nSECURE_FRAME_DENY               = False\n\n\n\n"
  },
  {
    "path": "src/ecommerce/settings/local.py",
    "content": "\"\"\"\nDjango settings for ecommerce project.\n\nGenerated by 'django-admin startproject' using Django 1.11.4.\n\nFor more information on this file, see\nhttps://docs.djangoproject.com/en/1.11/topics/settings/\n\nFor the full list of settings and their values, see\nhttps://docs.djangoproject.com/en/1.11/ref/settings/\n\"\"\"\n\nimport os\n\n# Build paths inside the project like this: os.path.join(BASE_DIR, ...)\nBASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))\n\n# Quick-start development settings - unsuitable for production\n# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/\n\n# SECURITY WARNING: keep the secret key used in production secret!\nSECRET_KEY = '@!-)jwmuzh8btr380g61=g+#&zzei&dz2(&=xbvxztady)_p(r'\n\n# SECURITY WARNING: don't run with debug turned on in production!\nDEBUG = True\n\nALLOWED_HOSTS = ['0.0.0.0', '127.0.0.1']\n\nEMAIL_HOST = 'smtp.gmail.com'\nEMAIL_HOST_USER = 'hungrypy@gmail.com' # sendgrid\nEMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD', 'yourpassword')\nEMAIL_PORT = 587\nEMAIL_USE_TLS = True\nDEFAULT_FROM_EMAIL = 'Python ecommerce <hungrypy@gmail.com>'\nBASE_URL = '127.0.0.1:8000'\n\nMANAGERS = (\n    ('Justin Mitchel', \"hungrypy@gmail.com\"),\n)\n\nADMINS = MANAGERS\n\n# Application definition\n\nINSTALLED_APPS = [\n    'django.contrib.admin',\n    'django.contrib.auth',\n    'django.contrib.contenttypes',\n    'django.contrib.sessions',\n    'django.contrib.messages',\n    'django.contrib.staticfiles',\n    # third party\n    'storages',\n\n    #our apps\n    'accounts',\n    'addresses',\n    'analytics',\n    'billing',\n    'carts',\n    'marketing',\n    'orders',\n    'products',\n    'search',\n    'tags',\n]\n\nAUTH_USER_MODEL = 'accounts.User' #changes the built-in user model to ours\nLOGIN_URL = '/login/'\nLOGIN_URL_REDIRECT = '/'\nLOGOUT_URL = '/logout/'\n\nFORCE_SESSION_TO_ONE = False\nFORCE_INACTIVE_USER_ENDSESSION= False\n\n\n\nMAILCHIMP_API_KEY = os.environ.get(\"MAILCHIMP_API_KEY\")\nMAILCHIMP_DATA_CENTER = \"us17\"\nMAILCHIMP_EMAIL_LIST_ID = os.environ.get(\"MAILCHIMP_EMAIL_LIST_ID\")\n\n\nSTRIPE_SECRET_KEY = os.environ.get(\"STRIPE_SECRET_KEY\", \"sk_test_cu1lQmcg1OLffhLvYrSCp5XE\")\nSTRIPE_PUB_KEY = os.environ.get(\"STRIPE_PUB_KEY\", 'pk_test_PrV61avxnHaWIYZEeiYTTVMZ')\n\n\nMIDDLEWARE = [\n    'django.middleware.security.SecurityMiddleware',\n    'django.contrib.sessions.middleware.SessionMiddleware',\n    'django.middleware.common.CommonMiddleware',\n    'django.middleware.csrf.CsrfViewMiddleware',\n    'django.contrib.auth.middleware.AuthenticationMiddleware',\n    'django.contrib.messages.middleware.MessageMiddleware',\n    'django.middleware.clickjacking.XFrameOptionsMiddleware',\n]\n\nLOGOUT_REDIRECT_URL = '/login/'\nROOT_URLCONF = 'ecommerce.urls'\n\nTEMPLATES = [\n    {\n        'BACKEND': 'django.template.backends.django.DjangoTemplates',\n        'DIRS': [os.path.join(BASE_DIR, 'templates')],\n        'APP_DIRS': True,\n        'OPTIONS': {\n            'context_processors': [\n                'django.template.context_processors.debug',\n                'django.template.context_processors.request',\n                'django.contrib.auth.context_processors.auth',\n                'django.contrib.messages.context_processors.messages',\n            ],\n        },\n    },\n]\n\nWSGI_APPLICATION = 'ecommerce.wsgi.application'\n\n\n# Database\n# https://docs.djangoproject.com/en/1.11/ref/settings/#databases\n\nDATABASES = {\n    'default': {\n        'ENGINE': 'django.db.backends.sqlite3',\n        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),\n    }\n}\n\n\n# Password validation\n# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators\n\nAUTH_PASSWORD_VALIDATORS = [\n    {\n        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',\n    },\n]\n\n\n# Internationalization\n# https://docs.djangoproject.com/en/1.11/topics/i18n/\n\nLANGUAGE_CODE = 'en-us'\n\nTIME_ZONE = 'America/Los_Angeles' #'UTC'\n\nUSE_I18N = True\n\nUSE_L10N = True\n\nUSE_TZ = True\n\n\n# Static files (CSS, JavaScript, Images)\n# https://docs.djangoproject.com/en/1.11/howto/static-files/\n\nSTATIC_URL = '/static/'\n\nSTATICFILES_DIRS = [\n    os.path.join(BASE_DIR, \"static_my_proj\"),\n]\n\nSTATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), \"static_cdn\", \"static_root\")\n\n\nMEDIA_URL = '/media/'\nMEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR), \"static_cdn\", \"media_root\")\n\n\nPROTECTED_ROOT = os.path.join(os.path.dirname(BASE_DIR), \"static_cdn\", \"protected_media\")\n\nfrom ecommerce.aws.conf import *\n\n\nCORS_REPLACE_HTTPS_REFERER      = False\nHOST_SCHEME                     = \"http://\"\nSECURE_PROXY_SSL_HEADER         = None\nSECURE_SSL_REDIRECT             = False\nSESSION_COOKIE_SECURE           = False\nCSRF_COOKIE_SECURE              = False\nSECURE_HSTS_SECONDS             = None\nSECURE_HSTS_INCLUDE_SUBDOMAINS  = False\nSECURE_FRAME_DENY               = False\n\n\n\n\n\n"
  },
  {
    "path": "src/ecommerce/settings/production.py",
    "content": "\"\"\"\nDjango settings for ecommerce project.\n\nGenerated by 'django-admin startproject' using Django 1.11.4.\n\nFor more information on this file, see\nhttps://docs.djangoproject.com/en/1.11/topics/settings/\n\nFor the full list of settings and their values, see\nhttps://docs.djangoproject.com/en/1.11/ref/settings/\n\"\"\"\n\nimport os\n\n# Build paths inside the project like this: os.path.join(BASE_DIR, ...)\nBASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))\n\n\n# Quick-start development settings - unsuitable for production\n# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/\n\n# SECURITY WARNING: keep the secret key used in production secret!\nSECRET_KEY = os.environ.get('SECRET_KEY')\n\n\n\nEMAIL_HOST = 'smtp.gmail.com'\nEMAIL_HOST_USER = 'hungrypy@gmail.com' \nEMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD')\nEMAIL_PORT = 587\nEMAIL_USE_TLS = True\nDEFAULT_FROM_EMAIL = 'Python ecommerce <hungrypy@gmail.com>'\nBASE_URL = 'https://www.pythonecommerce.com/'\n\nMANAGERS = (\n    ('Justin Mitchel', \"hungrypy@gmail.com\"),\n)\n\nADMINS = MANAGERS\n\n\n\n# SECURITY WARNING: don't run with debug turned on in production!\nDEBUG = False\n\nALLOWED_HOSTS = ['.pythonecommerce.com']\n\n\n# Application definition\n\nINSTALLED_APPS = [\n    'django.contrib.admin',\n    'django.contrib.auth',\n    'django.contrib.contenttypes',\n    'django.contrib.sessions',\n    'django.contrib.messages',\n    'django.contrib.staticfiles',\n    # third party\n    'storages',\n\n    #our apps\n    'accounts',\n    'addresses',\n    'analytics',\n    'billing',\n    'carts',\n    'marketing',\n    'orders',\n    'products',\n    'search',\n    'tags',\n]\n\nAUTH_USER_MODEL = 'accounts.User' #changes the built-in user model to ours\nLOGIN_URL = '/login/'\nLOGIN_URL_REDIRECT = '/'\nLOGOUT_URL = '/logout/'\n\nFORCE_SESSION_TO_ONE = False\nFORCE_INACTIVE_USER_ENDSESSION= False\n\n\n\nMAILCHIMP_API_KEY = os.environ.get(\"MAILCHIMP_API_KEY\")\nMAILCHIMP_DATA_CENTER = \"us17\"\nMAILCHIMP_EMAIL_LIST_ID = os.environ.get(\"MAILCHIMP_EMAIL_LIST_ID\")\n\n\nSTRIPE_SECRET_KEY = os.environ.get(\"STRIPE_SECRET_KEY\", \"sk_test_cu1lQmcg1OLffhLvYrSCp5XE\")\nSTRIPE_PUB_KEY = os.environ.get(\"STRIPE_PUB_KEY\", 'pk_test_PrV61avxnHaWIYZEeiYTTVMZ')\n\n\nMIDDLEWARE = [\n    'django.middleware.security.SecurityMiddleware',\n    'django.contrib.sessions.middleware.SessionMiddleware',\n    'django.middleware.common.CommonMiddleware',\n    'django.middleware.csrf.CsrfViewMiddleware',\n    'django.contrib.auth.middleware.AuthenticationMiddleware',\n    'django.contrib.messages.middleware.MessageMiddleware',\n    'django.middleware.clickjacking.XFrameOptionsMiddleware',\n]\n\nLOGOUT_REDIRECT_URL = '/login/'\nROOT_URLCONF = 'ecommerce.urls'\n\nTEMPLATES = [\n    {\n        'BACKEND': 'django.template.backends.django.DjangoTemplates',\n        'DIRS': [os.path.join(BASE_DIR, 'templates')],\n        'APP_DIRS': True,\n        'OPTIONS': {\n            'context_processors': [\n                'django.template.context_processors.debug',\n                'django.template.context_processors.request',\n                'django.contrib.auth.context_processors.auth',\n                'django.contrib.messages.context_processors.messages',\n            ],\n        },\n    },\n]\n\nWSGI_APPLICATION = 'ecommerce.wsgi.application'\n\n\n# Database\n# https://docs.djangoproject.com/en/1.11/ref/settings/#databases\n\nDATABASES = {\n    'default': {\n        'ENGINE': 'django.db.backends.sqlite3',\n        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),\n    }\n}\n\nimport dj_database_url\ndb_from_env = dj_database_url.config() #postgreSQL Database in heroku\nDATABASES['default'].update(db_from_env)\nDATABASES['default']['CONN_MAX_AGE'] = 500\n\n\n# Password validation\n# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators\n\nAUTH_PASSWORD_VALIDATORS = [\n    {\n        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',\n    },\n]\n\n\n# Internationalization\n# https://docs.djangoproject.com/en/1.11/topics/i18n/\n\nLANGUAGE_CODE = 'en-us'\n\nTIME_ZONE = 'UTC'\n\nUSE_I18N = True\n\nUSE_L10N = True\n\nUSE_TZ = True\n\n\n# Static files (CSS, JavaScript, Images)\n# https://docs.djangoproject.com/en/1.11/howto/static-files/\n\nSTATIC_URL = '/static/'\n\nSTATICFILES_DIRS = [\n    os.path.join(BASE_DIR, \"static_my_proj\"),\n]\n\nSTATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), \"static_cdn\", \"static_root\")\n\n\nMEDIA_URL = '/media/'\nMEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR), \"static_cdn\", \"media_root\")\n\n\nPROTECTED_ROOT = os.path.join(os.path.dirname(BASE_DIR), \"static_cdn\", \"protected_media\")\n\nfrom ecommerce.aws.conf import *\n\n\n# https://kirr.co/vklau5\n\n# Let's Encrypt ssl/tls https\n\nCORS_REPLACE_HTTPS_REFERER      = True\nHOST_SCHEME                     = \"https://\"\nSECURE_PROXY_SSL_HEADER         = ('HTTP_X_FORWARDED_PROTO', 'https')\nSECURE_SSL_REDIRECT             = True\nSESSION_COOKIE_SECURE           = True\nCSRF_COOKIE_SECURE              = True\nSECURE_HSTS_INCLUDE_SUBDOMAINS  = True\nSECURE_HSTS_SECONDS             = 1000000\nSECURE_FRAME_DENY               = True\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "src/ecommerce/urls.py",
    "content": "\"\"\"ecommerce URL Configuration\n\nThe `urlpatterns` list routes URLs to views. For more information please see:\n    https://docs.djangoproject.com/en/1.11/topics/http/urls/\nExamples:\nFunction views\n    1. Add an import:  from my_app import views\n    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')\nClass-based views\n    1. Add an import:  from other_app.views import Home\n    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')\nIncluding another URLconf\n    1. Import the include() function: from django.conf.urls import url, include\n    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))\n\"\"\"\n\nfrom django.conf import settings\nfrom django.conf.urls.static import static\n\nfrom django.conf.urls import url, include\nfrom django.contrib import admin\nfrom django.contrib.auth.views import LogoutView\nfrom django.views.generic import TemplateView, RedirectView\n\n\nfrom accounts.views import LoginView, RegisterView, GuestRegisterView\nfrom addresses.views import (\n    AddressCreateView,\n    AddressListView,\n    AddressUpdateView,\n    checkout_address_create_view, \n    checkout_address_reuse_view\n    )\nfrom analytics.views import SalesView, SalesAjaxView\nfrom billing.views import payment_method_view, payment_method_createview\nfrom carts.views import cart_detail_api_view\nfrom marketing.views import MarketingPreferenceUpdateView, MailchimpWebhookView\nfrom orders.views import LibraryView\n\nfrom .views import home_page, about_page, contact_page\n\nurlpatterns = [\n    url(r'^$', home_page, name='home'),\n    url(r'^about/$', about_page, name='about'),\n    #url(r'^accounts/login/$', RedirectView.as_view(url='/login')),\n    url(r'^accounts/$', RedirectView.as_view(url='/account')),\n    url(r'^account/', include(\"accounts.urls\", namespace='account')),\n    url(r'^accounts/', include(\"accounts.passwords.urls\")),\n    url(r'^address/$', RedirectView.as_view(url='/addresses')),\n    url(r'^addresses/$', AddressListView.as_view(), name='addresses'),\n    url(r'^addresses/create/$', AddressCreateView.as_view(), name='address-create'),\n    url(r'^addresses/(?P<pk>\\d+)/$', AddressUpdateView.as_view(), name='address-update'),\n    url(r'^analytics/sales/$', SalesView.as_view(), name='sales-analytics'),\n    url(r'^analytics/sales/data/$', SalesAjaxView.as_view(), name='sales-analytics-data'),\n    url(r'^contact/$', contact_page, name='contact'),\n    url(r'^login/$', LoginView.as_view(), name='login'),\n    url(r'^checkout/address/create/$', checkout_address_create_view, name='checkout_address_create'),\n    url(r'^checkout/address/reuse/$', checkout_address_reuse_view, name='checkout_address_reuse'),\n    url(r'^register/guest/$', GuestRegisterView.as_view(), name='guest_register'),\n    url(r'^logout/$', LogoutView.as_view(), name='logout'),\n    url(r'^api/cart/$', cart_detail_api_view, name='api-cart'),\n    url(r'^cart/', include(\"carts.urls\", namespace='cart')),\n    url(r'^billing/payment-method/$', payment_method_view, name='billing-payment-method'),\n    url(r'^billing/payment-method/create/$', payment_method_createview, name='billing-payment-method-endpoint'),\n    url(r'^register/$', RegisterView.as_view(), name='register'),\n    url(r'^bootstrap/$', TemplateView.as_view(template_name='bootstrap/example.html')),\n    url(r'^library/$', LibraryView.as_view(), name='library'),\n    url(r'^orders/', include(\"orders.urls\", namespace='orders')),\n    url(r'^products/', include(\"products.urls\", namespace='products')),\n    url(r'^search/', include(\"search.urls\", namespace='search')),\n    url(r'^settings/$', RedirectView.as_view(url='/account')),\n    url(r'^settings/email/$', MarketingPreferenceUpdateView.as_view(), name='marketing-pref'),\n    url(r'^webhooks/mailchimp/$', MailchimpWebhookView.as_view(), name='webhooks-mailchimp'),\n    url(r'^admin/', admin.site.urls),\n]\n\n\nif settings.DEBUG:\n    urlpatterns = urlpatterns + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)\n    urlpatterns = urlpatterns + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)\n"
  },
  {
    "path": "src/ecommerce/utils.py",
    "content": "\nimport datetime \nimport os\nimport random\nimport string\n\nfrom django.utils import timezone\nfrom django.utils.text import slugify\n\n\n\ndef get_last_month_data(today):\n    '''\n    Simple method to get the datetime objects for the \n    start and end of last month. \n    '''\n    this_month_start = datetime.datetime(today.year, today.month, 1)\n    last_month_end = this_month_start - datetime.timedelta(days=1)\n    last_month_start = datetime.datetime(last_month_end.year, last_month_end.month, 1)\n    return (last_month_start, last_month_end)\n\n\ndef get_month_data_range(months_ago=1, include_this_month=False):\n    '''\n    A method that generates a list of dictionaires \n    that describe any given amout of monthly data.\n    '''\n    today = datetime.datetime.now().today()\n    dates_ = []\n    if include_this_month:\n        # get next month's data with:\n        next_month = today.replace(day=28) + datetime.timedelta(days=4)\n        # use next month's data to get this month's data breakdown\n        start, end = get_last_month_data(next_month)\n        dates_.insert(0, {\n            \"start\": start.timestamp(),\n            \"end\": end.timestamp(),\n            \"start_json\": start.isoformat(),\n            \"end\": end.timestamp(),\n            \"end_json\": end.isoformat(),\n            \"timesince\": 0,\n            \"year\": start.year,\n            \"month\": str(start.strftime(\"%B\")),\n            })\n    for x in range(0, months_ago):\n        start, end = get_last_month_data(today)\n        today = start\n        dates_.insert(0, {\n            \"start\": start.timestamp(),\n            \"start_json\": start.isoformat(),\n            \"end\": end.timestamp(),\n            \"end_json\": end.isoformat(),\n            \"timesince\": int((datetime.datetime.now() - end).total_seconds()),\n            \"year\": start.year,\n            \"month\": str(start.strftime(\"%B\"))\n        })\n    #dates_.reverse()\n    return dates_ \n\n\ndef get_filename(path): #/abc/filename.mp4\n    return os.path.basename(path)\n\n\ndef random_string_generator(size=10, chars=string.ascii_lowercase + string.digits):\n    return ''.join(random.choice(chars) for _ in range(size))\n\n\ndef unique_key_generator(instance):\n    \"\"\"\n    This is for a Django project with an key field\n    \"\"\"\n    size = random.randint(30, 45)\n    key = random_string_generator(size=size)\n\n    Klass = instance.__class__\n    qs_exists = Klass.objects.filter(key=key).exists()\n    if qs_exists:\n        return unique_slug_generator(instance)\n    return key\n\n\ndef unique_order_id_generator(instance):\n    \"\"\"\n    This is for a Django project with an order_id field\n    \"\"\"\n    order_new_id = random_string_generator()\n\n    Klass = instance.__class__\n    qs_exists = Klass.objects.filter(order_id=order_new_id).exists()\n    if qs_exists:\n        return unique_slug_generator(instance)\n    return order_new_id\n\n\n\n\n\ndef unique_slug_generator(instance, new_slug=None):\n    \"\"\"\n    This is for a Django project and it assumes your instance \n    has a model with a slug field and a title character (char) field.\n    \"\"\"\n    if new_slug is not None:\n        slug = new_slug\n    else:\n        slug = slugify(instance.title)\n\n    Klass = instance.__class__\n    qs_exists = Klass.objects.filter(slug=slug).exists()\n    if qs_exists:\n        new_slug = \"{slug}-{randstr}\".format(\n                    slug=slug,\n                    randstr=random_string_generator(size=4)\n                )\n        return unique_slug_generator(instance, new_slug=new_slug)\n    return slug"
  },
  {
    "path": "src/ecommerce/views.py",
    "content": "from django.contrib.auth import authenticate, login, get_user_model\nfrom django.http import HttpResponse, JsonResponse\nfrom django.shortcuts import render,redirect\n\nfrom .forms import ContactForm\n\ndef home_page(request):\n    # print(request.session.get(\"first_name\", \"Unknown\"))\n    # request.session['first_name']\n    context = {\n        \"title\":\"Hello World!\",\n        \"content\":\" Welcome to the homepage.\",\n\n    }\n    if request.user.is_authenticated():\n        context[\"premium_content\"] = \"YEAHHHHHH\"\n    return render(request, \"home_page.html\", context)\n\ndef about_page(request):\n    context = {\n        \"title\":\"About Page\",\n        \"content\":\" Welcome to the about page.\"\n    }\n    return render(request, \"home_page.html\", context)\n\ndef contact_page(request):\n    contact_form = ContactForm(request.POST or None)\n    context = {\n        \"title\":\"Contact\",\n        \"content\":\" Welcome to the contact page.\",\n        \"form\": contact_form,\n    }\n    if contact_form.is_valid():\n        print(contact_form.cleaned_data)\n        if request.is_ajax():\n            return JsonResponse({\"message\": \"Thank you for your submission\"})\n\n    if contact_form.errors:\n        errors = contact_form.errors.as_json()\n        if request.is_ajax():\n            return HttpResponse(errors, status=400, content_type='application/json')\n\n    # if request.method == \"POST\":\n    #     #print(request.POST)\n    #     print(request.POST.get('fullname'))\n    #     print(request.POST.get('email'))\n    #     print(request.POST.get('content'))\n    return render(request, \"contact/view.html\", context)\n\n\n\n\n\ndef home_page_old(request):\n    html_ = \"\"\"\n    <!DOCTYPE html>\n    <html lang=\"en\">\n      <head>\n        <!-- Required meta tags -->\n        <meta charset=\"utf-8\">\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n\n        <!-- Bootstrap CSS -->\n        <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n      </head>\n      <body>\n        <div class='text-center'>\n            <h1>Hello, world!</h1>\n        </div>\n        <!-- Optional JavaScript -->\n        <!-- jQuery first, then Popper.js, then Bootstrap JS -->\n        <script src=\"https://code.jquery.com/jquery-3.2.1.slim.min.js\" integrity=\"sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN\" crossorigin=\"anonymous\"></script>\n        <script src=\"https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js\" integrity=\"sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4\" crossorigin=\"anonymous\"></script>\n        <script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js\" integrity=\"sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1\" crossorigin=\"anonymous\"></script>\n      </body>\n    </html>\n    \"\"\"\n    return HttpResponse(html_)\n\n\n"
  },
  {
    "path": "src/ecommerce/wsgi.py",
    "content": "\"\"\"\nWSGI config for ecommerce project.\n\nIt exposes the WSGI callable as a module-level variable named ``application``.\n\nFor more information on this file, see\nhttps://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/\n\"\"\"\n\nimport os\n\nfrom django.core.wsgi import get_wsgi_application\n\nos.environ.setdefault(\"DJANGO_SETTINGS_MODULE\", \"ecommerce.settings\")\n\napplication = get_wsgi_application()\n"
  },
  {
    "path": "src/manage.py",
    "content": "#!/usr/bin/env python\nimport os\nimport sys\n\nif __name__ == \"__main__\":\n    os.environ.setdefault(\"DJANGO_SETTINGS_MODULE\", \"ecommerce.settings\")\n    try:\n        from django.core.management import execute_from_command_line\n    except ImportError:\n        # The above import may fail for some other reason. Ensure that the\n        # issue is really that Django is missing to avoid masking other\n        # exceptions on Python 2.\n        try:\n            import django\n        except ImportError:\n            raise ImportError(\n                \"Couldn't import Django. Are you sure it's installed and \"\n                \"available on your PYTHONPATH environment variable? Did you \"\n                \"forget to activate a virtual environment?\"\n            )\n        raise\n    execute_from_command_line(sys.argv)\n"
  },
  {
    "path": "src/marketing/__init__.py",
    "content": ""
  },
  {
    "path": "src/marketing/admin.py",
    "content": "from django.contrib import admin\n\nfrom .models import MarketingPreference\n\nclass MarketingPreferenceAdmin(admin.ModelAdmin):\n    list_display  = ['__str__', 'subscribed', 'updated']\n    readonly_fields = ['mailchimp_msg', 'mailchimp_subscribed', 'timestamp', 'updated']\n    class Meta:\n        model = MarketingPreference\n        fields = [\n                    'user', \n                    'subscribed', \n                    'mailchimp_msg',\n                    'mailchimp_subscribed', \n                    'timestamp', \n                    'updated'\n                ]\n\nadmin.site.register(MarketingPreference, MarketingPreferenceAdmin)"
  },
  {
    "path": "src/marketing/apps.py",
    "content": "from django.apps import AppConfig\n\n\nclass MarketingConfig(AppConfig):\n    name = 'marketing'\n"
  },
  {
    "path": "src/marketing/forms.py",
    "content": "from django import forms\n\nfrom .models import MarketingPreference\n\n\nclass MarketingPreferenceForm(forms.ModelForm):\n    subscribed = forms.BooleanField(label='Receive Marketing Email?', required=False)\n    class Meta:\n        model = MarketingPreference\n        fields = [\n            'subscribed'\n        ]"
  },
  {
    "path": "src/marketing/migrations/0001_initial.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-18 00:36\nfrom __future__ import unicode_literals\n\nfrom django.conf import settings\nfrom django.db import migrations, models\nimport django.db.models.deletion\n\n\nclass Migration(migrations.Migration):\n\n    initial = True\n\n    dependencies = [\n        migrations.swappable_dependency(settings.AUTH_USER_MODEL),\n    ]\n\n    operations = [\n        migrations.CreateModel(\n            name='MarketingPreference',\n            fields=[\n                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),\n                ('subscribed', models.BooleanField(default=True)),\n                ('mailchimp_msg', models.TextField(blank=True, null=True)),\n                ('timestamp', models.DateTimeField(auto_now_add=True)),\n                ('update', models.DateTimeField(auto_now=True)),\n                ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),\n            ],\n        ),\n    ]\n"
  },
  {
    "path": "src/marketing/migrations/0002_marketingpreference_mailchimp_subscribed.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-18 01:34\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('marketing', '0001_initial'),\n    ]\n\n    operations = [\n        migrations.AddField(\n            model_name='marketingpreference',\n            name='mailchimp_subscribed',\n            field=models.NullBooleanField(),\n        ),\n    ]\n"
  },
  {
    "path": "src/marketing/migrations/0003_auto_20171018_0142.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-18 01:42\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('marketing', '0002_marketingpreference_mailchimp_subscribed'),\n    ]\n\n    operations = [\n        migrations.RenameField(\n            model_name='marketingpreference',\n            old_name='update',\n            new_name='updated',\n        ),\n    ]\n"
  },
  {
    "path": "src/marketing/migrations/__init__.py",
    "content": ""
  },
  {
    "path": "src/marketing/mixins.py",
    "content": "from django.utils.decorators import method_decorator\nfrom django.views.decorators.csrf import csrf_exempt\n\n\nclass CsrfExemptMixin(object):\n    @method_decorator(csrf_exempt)\n    def dispatch(self, request, *args, **kwargs):\n        return super(CsrfExemptMixin, self).dispatch(request, *args, **kwargs)\n\n"
  },
  {
    "path": "src/marketing/models.py",
    "content": "from django.conf import settings\nfrom django.db import models\nfrom django.db.models.signals import post_save, pre_save\n\nfrom .utils import Mailchimp\n\nclass MarketingPreference(models.Model):\n    user                        = models.OneToOneField(settings.AUTH_USER_MODEL)\n    subscribed                  = models.BooleanField(default=True)\n    mailchimp_subscribed        = models.NullBooleanField(blank=True)\n    mailchimp_msg               = models.TextField(null=True, blank=True)\n    timestamp                   = models.DateTimeField(auto_now_add=True)\n    updated                      = models.DateTimeField(auto_now=True)\n\n    def __str__(self):\n        return self.user.email\n\n\n\n\ndef marketing_pref_create_receiver(sender, instance, created, *args, **kwargs):\n    if created:\n        status_code, response_data = Mailchimp().subscribe(instance.user.email)\n        print(status_code, response_data)\n\n\npost_save.connect(marketing_pref_create_receiver, sender=MarketingPreference)\n\ndef marketing_pref_update_receiver(sender, instance, *args, **kwargs):\n    if instance.subscribed != instance.mailchimp_subscribed:\n        if instance.subscribed:\n            # subscribing user\n            status_code, response_data = Mailchimp().subscribe(instance.user.email)\n        else:\n            # unsubscribing user\n            status_code, response_data = Mailchimp().unsubscribe(instance.user.email)\n\n        if response_data['status'] == 'subscribed':\n            instance.subscribed = True\n            instance.mailchimp_subscribed = True\n            instance.mailchimp_msg = response_data\n        else:\n            instance.subscribed = False\n            instance.mailchimp_subscribed = False\n            instance.mailchimp_msg = response_data\n\npre_save.connect(marketing_pref_update_receiver, sender=MarketingPreference)\n\n\n\ndef make_marketing_pref_receiver(sender, instance, created, *args, **kwargs):\n    '''\n    User model\n    '''\n    if created:\n        MarketingPreference.objects.get_or_create(user=instance)\n\npost_save.connect(make_marketing_pref_receiver, sender=settings.AUTH_USER_MODEL)\n\n\n\n"
  },
  {
    "path": "src/marketing/tests.py",
    "content": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "src/marketing/utils.py",
    "content": "import hashlib\nimport json\nimport re\nimport requests\nfrom django.conf import settings\n\n\nMAILCHIMP_API_KEY = getattr(settings, \"MAILCHIMP_API_KEY\", None)\nMAILCHIMP_DATA_CENTER = getattr(settings, \"MAILCHIMP_DATA_CENTER\", None)\nMAILCHIMP_EMAIL_LIST_ID = getattr(settings, \"MAILCHIMP_EMAIL_LIST_ID\", None)\n\n\n\ndef check_email(email):\n    if not re.match(r\".+@.+\\..+\", email):\n        raise ValueError('String passed is not a valid email address')\n    return email\n\ndef get_subscriber_hash(member_email):\n    check_email(member_email)\n    member_email = member_email.lower().encode()\n    m = hashlib.md5(member_email)\n    return m.hexdigest()\n\n\n\nclass Mailchimp(object):\n    def __init__(self):\n        super(Mailchimp, self).__init__()\n        self.key = MAILCHIMP_API_KEY\n        self.api_url = \"https://{dc}.api.mailchimp.com/3.0\".format(\n                    dc=MAILCHIMP_DATA_CENTER\n                    )\n        self.list_id = MAILCHIMP_EMAIL_LIST_ID\n        self.list_endpoint = '{api_url}/lists/{list_id}'.format(\n                                    api_url = self.api_url,\n                                    list_id=self.list_id\n                        )\n\n    \n    def get_members_endpoint(self):\n        return self.list_endpoint + \"/members\"\n\n    def change_subcription_status(self, email, status='unsubscribed'):\n        hashed_email = get_subscriber_hash(email)\n        endpoint = self.get_members_endpoint() + \"/\" +  hashed_email\n        data = {\n            \"status\": self.check_valid_status(status)\n        }\n        r = requests.put(endpoint, auth=(\"\", self.key), data=json.dumps(data))\n        return r.status_code, r.json()\n\n\n    def check_subcription_status(self, email):\n        hashed_email = get_subscriber_hash(email)\n        endpoint = self.get_members_endpoint() + \"/\" +  hashed_email\n        r = requests.get(endpoint, auth=(\"\", self.key))\n        return r.status_code, r.json()\n\n    def check_valid_status(self, status):\n        choices = ['subscribed', 'unsubscribed', 'cleaned', 'pending']\n        if status not in choices:\n            raise ValueError(\"Not a valid choice for email status\")\n        return status\n\n    def add_email(self, email):\n        # status = \"subscribed\"\n        # self.check_valid_status(status)\n        # data = {\n        #     \"email_address\": email,\n        #     \"status\": status\n        # }\n        # endpoint = self.get_members_endpoint()\n        # r = requests.post(endpoint, auth=(\"\", self.key), data=json.dumps(data))\n        return self.change_subcription_status(email, status='subscribed')\n\n    def unsubscribe(self, email):\n        return self.change_subcription_status(email, status='unsubscribed')\n\n    def subscribe(self, email):\n        return self.change_subcription_status(email, status='subscribed')\n\n    def pending(self, email):\n        return self.change_subcription_status(email, status='pending')\n\n"
  },
  {
    "path": "src/marketing/views.py",
    "content": "from django.conf import settings\n\nfrom django.contrib.messages.views import SuccessMessageMixin\nfrom django.http import HttpResponse\nfrom django.views.generic import UpdateView, View\nfrom django.shortcuts import render, redirect\n\n\nfrom .forms import MarketingPreferenceForm\nfrom .mixins import CsrfExemptMixin\nfrom .models import MarketingPreference\nfrom .utils import Mailchimp\nMAILCHIMP_EMAIL_LIST_ID = getattr(settings, \"MAILCHIMP_EMAIL_LIST_ID\", None)\n\nclass MarketingPreferenceUpdateView(SuccessMessageMixin, UpdateView):\n    form_class = MarketingPreferenceForm\n    template_name = 'base/forms.html' # yeah create this\n    success_url = '/settings/email/'\n    success_message = 'Your email preferences have been updated. Thank you.'\n\n    def dispatch(self, *args, **kwargs):\n        user = self.request.user\n        if not user.is_authenticated():\n            return redirect(\"/login/?next=/settings/email/\") # HttpResponse(\"Not allowed\", status=400)\n        return super(MarketingPreferenceUpdateView, self).dispatch(*args, **kwargs)\n\n    def get_context_data(self, *args, **kwargs):\n        context = super(MarketingPreferenceUpdateView, self).get_context_data(*args, **kwargs)\n        context['title'] = 'Update Email Preferences'\n        return context\n\n    def get_object(self):\n        user = self.request.user\n        obj, created = MarketingPreference.objects.get_or_create(user=user) # get_absolute_url\n        return obj\n\n\n\n\n\n\n\"\"\"\nPOST METHOD\ndata[list_id]: e2ef12efee\nfired_at: 2017-10-18 18:49:49\ndata[merges][FNAME]:\ndata[email]: hello@teamcfe.com\ndata[merges][LNAME]:\ndata[email_type]: html\ndata[reason]: manual\ndata[merges][BIRTHDAY]:\ndata[id]: d686033a32\ndata[merges][EMAIL]: hello@teamcfe.com\ndata[ip_opt]: 108.184.68.3\ndata[web_id]: 349661\ntype: unsubscribe\ndata[action]: unsub\n\"\"\"\n\nclass MailchimpWebhookView(CsrfExemptMixin, View): # HTTP GET -- def get() CSRF?????\n    # def get(self, request, *args, **kwargs):\n    #     return HttpResponse(\"Thank you\", status=200)\n    def post(self, request, *args, **kwargs):\n        data = request.POST\n        list_id = data.get('data[list_id]')\n        if str(list_id) == str(MAILCHIMP_EMAIL_LIST_ID):\n            hook_type = data.get(\"type\")\n            email = data.get('data[email]')\n            response_status, response = Mailchimp().check_subcription_status(email)\n            sub_status  = response['status']\n            is_subbed = None\n            mailchimp_subbed = None\n            if sub_status == \"subscribed\":\n                is_subbed, mailchimp_subbed  = (True, True)\n            elif sub_status == \"unsubscribed\":\n                is_subbed, mailchimp_subbed  = (False, False)\n            if is_subbed is not None and mailchimp_subbed is not None:\n                qs = MarketingPreference.objects.filter(user__email__iexact=email)\n                if qs.exists():\n                    qs.update(\n                            subscribed=is_subbed, \n                            mailchimp_subscribed=mailchimp_subbed, \n                            mailchimp_msg=str(data))\n        return HttpResponse(\"Thank you\", status=200)\n\n# def mailchimp_webhook_view(request):\n#     data = request.POST\n#     list_id = data.get('data[list_id]')\n#     if str(list_id) == str(MAILCHIMP_EMAIL_LIST_ID):\n#         hook_type = data.get(\"type\")\n#         email = data.get('data[email]')\n#         response_status, response = Mailchimp().check_subcription_status(email)\n#         sub_status  = response['status']\n#         is_subbed = None\n#         mailchimp_subbed = None\n#         if sub_status == \"subscribed\":\n#             is_subbed, mailchimp_subbed  = (True, True)\n#         elif sub_status == \"unsubscribed\":\n#             is_subbed, mailchimp_subbed  = (False, False)\n#         if is_subbed is not None and mailchimp_subbed is not None:\n#             qs = MarketingPreference.objects.filter(user__email__iexact=email)\n#             if qs.exists():\n#                 qs.update(\n#                         subscribed=is_subbed, \n#                         mailchimp_subscribed=mailchimp_subbed, \n#                         mailchimp_msg=str(data))\n#     return HttpResponse(\"Thank you\", status=200)\n\n\n\n"
  },
  {
    "path": "src/orders/__init__.py",
    "content": ""
  },
  {
    "path": "src/orders/admin.py",
    "content": "from django.contrib import admin\n\nfrom .models import Order, ProductPurchase\n\nadmin.site.register(Order)\n\nadmin.site.register(ProductPurchase)"
  },
  {
    "path": "src/orders/apps.py",
    "content": "from django.apps import AppConfig\n\n\nclass OrdersConfig(AppConfig):\n    name = 'orders'\n"
  },
  {
    "path": "src/orders/migrations/0001_initial.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-27 23:00\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\nimport django.db.models.deletion\n\n\nclass Migration(migrations.Migration):\n\n    initial = True\n\n    dependencies = [\n        ('carts', '0002_cart_subtotal'),\n    ]\n\n    operations = [\n        migrations.CreateModel(\n            name='Order',\n            fields=[\n                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),\n                ('order_id', models.CharField(blank=True, max_length=120)),\n                ('status', models.CharField(choices=[('created', 'Created'), ('paid', 'Paid'), ('shipped', 'Shipped'), ('refunded', 'Refunded')], default='created', max_length=120)),\n                ('shipping_total', models.DecimalField(decimal_places=2, default=5.99, max_digits=100)),\n                ('total', models.DecimalField(decimal_places=2, default=0.0, max_digits=100)),\n                ('cart', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='carts.Cart')),\n            ],\n        ),\n    ]\n"
  },
  {
    "path": "src/orders/migrations/0002_auto_20170928_2224.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-28 22:24\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\nimport django.db.models.deletion\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('billing', '0002_auto_20170928_2052'),\n        ('orders', '0001_initial'),\n    ]\n\n    operations = [\n        migrations.AddField(\n            model_name='order',\n            name='active',\n            field=models.BooleanField(default=True),\n        ),\n        migrations.AddField(\n            model_name='order',\n            name='billing_profile',\n            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='billing.BillingProfile'),\n        ),\n    ]\n"
  },
  {
    "path": "src/orders/migrations/0003_auto_20170929_0013.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-29 00:13\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\nimport django.db.models.deletion\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('addresses', '0001_initial'),\n        ('orders', '0002_auto_20170928_2224'),\n    ]\n\n    operations = [\n        migrations.AddField(\n            model_name='order',\n            name='billing_address',\n            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='billing_address', to='addresses.Address'),\n        ),\n        migrations.AddField(\n            model_name='order',\n            name='shipping_address',\n            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='shipping_address', to='addresses.Address'),\n        ),\n    ]\n"
  },
  {
    "path": "src/orders/migrations/0004_auto_20171025_2216.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-10-25 22:16\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\nimport django.utils.timezone\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('orders', '0003_auto_20170929_0013'),\n    ]\n\n    operations = [\n        migrations.AlterModelOptions(\n            name='order',\n            options={'ordering': ['-timestamp', '-updated']},\n        ),\n        migrations.AddField(\n            model_name='order',\n            name='timestamp',\n            field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),\n            preserve_default=False,\n        ),\n        migrations.AddField(\n            model_name='order',\n            name='updated',\n            field=models.DateTimeField(auto_now=True),\n        ),\n    ]\n"
  },
  {
    "path": "src/orders/migrations/0005_auto_20171107_0035.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-11-07 00:35\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('orders', '0004_auto_20171025_2216'),\n    ]\n\n    operations = [\n        migrations.AddField(\n            model_name='order',\n            name='billing_address_final',\n            field=models.TextField(blank=True, null=True),\n        ),\n        migrations.AddField(\n            model_name='order',\n            name='shipping_address_final',\n            field=models.TextField(blank=True, null=True),\n        ),\n    ]\n"
  },
  {
    "path": "src/orders/migrations/0006_productpurchase_productpurchasemanager.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-11-08 00:17\nfrom __future__ import unicode_literals\n\nfrom django.conf import settings\nfrom django.db import migrations, models\nimport django.db.models.deletion\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('products', '0010_product_is_digital'),\n        migrations.swappable_dependency(settings.AUTH_USER_MODEL),\n        ('billing', '0007_auto_20171012_1935'),\n        ('orders', '0005_auto_20171107_0035'),\n    ]\n\n    operations = [\n        migrations.CreateModel(\n            name='ProductPurchase',\n            fields=[\n                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),\n                ('refunded', models.BooleanField(default=False)),\n                ('updated', models.DateTimeField(auto_now=True)),\n                ('timestamp', models.DateTimeField(auto_now_add=True)),\n                ('billing_profile', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='billing.BillingProfile')),\n                ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='products.Product')),\n                ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),\n            ],\n        ),\n        migrations.CreateModel(\n            name='ProductPurchaseManager',\n            fields=[\n                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),\n            ],\n        ),\n    ]\n"
  },
  {
    "path": "src/orders/migrations/0007_auto_20171108_0028.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-11-08 00:28\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('orders', '0006_productpurchase_productpurchasemanager'),\n    ]\n\n    operations = [\n        migrations.RemoveField(\n            model_name='productpurchase',\n            name='user',\n        ),\n        migrations.AddField(\n            model_name='productpurchase',\n            name='order_id',\n            field=models.CharField(default='abc123', max_length=120),\n            preserve_default=False,\n        ),\n    ]\n"
  },
  {
    "path": "src/orders/migrations/0008_delete_productpurchasemanager.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-11-08 00:39\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('orders', '0007_auto_20171108_0028'),\n    ]\n\n    operations = [\n        migrations.DeleteModel(\n            name='ProductPurchaseManager',\n        ),\n    ]\n"
  },
  {
    "path": "src/orders/migrations/__init__.py",
    "content": ""
  },
  {
    "path": "src/orders/models.py",
    "content": "import math\nimport datetime\nfrom django.conf import settings\nfrom django.db import models\nfrom django.db.models import Count, Sum, Avg\nfrom django.db.models.signals import pre_save, post_save\nfrom django.core.urlresolvers import reverse\nfrom django.utils import timezone\n\nfrom addresses.models import Address\nfrom billing.models import BillingProfile\nfrom carts.models import Cart\nfrom ecommerce.utils import unique_order_id_generator\nfrom products.models import Product\n\nORDER_STATUS_CHOICES = (\n    ('created', 'Created'),\n    ('paid', 'Paid'),\n    ('shipped', 'Shipped'),\n    ('refunded', 'Refunded'),\n)\n\nclass OrderManagerQuerySet(models.query.QuerySet):\n    def recent(self):\n        return self.order_by(\"-updated\", \"-timestamp\")\n\n    def get_sales_breakdown(self):\n        recent = self.recent().not_refunded()\n        recent_data = recent.totals_data()\n        recent_cart_data = recent.cart_data()\n        shipped = recent.not_refunded().by_status(status='shipped')\n        shipped_data = shipped.totals_data()\n        paid = recent.by_status(status='paid')\n        paid_data = paid.totals_data()\n        data = {\n            'recent': recent,\n            'recent_data':recent_data,\n            'recent_cart_data': recent_cart_data,\n            'shipped': shipped,\n            'shipped_data': shipped_data,\n            'paid': paid,\n            'paid_data': paid_data\n        }\n        return data\n\n    def by_weeks_range(self, weeks_ago=7, number_of_weeks=2):\n        if number_of_weeks > weeks_ago:\n            number_of_weeks = weeks_ago\n        days_ago_start = weeks_ago * 7  # days_ago_start = 49\n        days_ago_end = days_ago_start - (number_of_weeks * 7) #days_ago_end = 49 - 14 = 35\n        start_date = timezone.now() - datetime.timedelta(days=days_ago_start)\n        end_date = timezone.now() - datetime.timedelta(days=days_ago_end) \n        return self.by_range(start_date, end_date=end_date)\n\n    def by_range(self, start_date, end_date=None):\n        if end_date is None:\n            return self.filter(updated__gte=start_date)\n        return self.filter(updated__gte=start_date).filter(updated__lte=end_date)\n\n    def by_date(self):\n        now = timezone.now() - datetime.timedelta(days=9)\n        return self.filter(updated__day__gte=now.day)\n\n    def totals_data(self):\n        return self.aggregate(Sum(\"total\"), Avg(\"total\"))\n\n    def cart_data(self):\n        return self.aggregate(\n                        Sum(\"cart__products__price\"), \n                        Avg(\"cart__products__price\"), \n                        Count(\"cart__products\")\n                                    )\n\n    def by_status(self, status=\"shipped\"):\n        return self.filter(status=status)\n\n    def not_refunded(self):\n        return self.exclude(status='refunded')\n\n    def by_request(self, request):\n        billing_profile, created = BillingProfile.objects.new_or_get(request)\n        return self.filter(billing_profile=billing_profile)\n\n    def not_created(self):\n        return self.exclude(status='created')\n\nclass OrderManager(models.Manager):\n    def get_queryset(self):\n        return OrderManagerQuerySet(self.model, using=self._db)\n\n    def by_request(self, request):\n        return self.get_queryset().by_request(request)\n\n    def new_or_get(self, billing_profile, cart_obj):\n        created = False\n        qs = self.get_queryset().filter(\n                billing_profile=billing_profile, \n                cart=cart_obj, \n                active=True, \n                status='created'\n            )\n        if qs.count() == 1:\n            obj = qs.first()\n        else:\n            obj = self.model.objects.create(\n                    billing_profile=billing_profile, \n                    cart=cart_obj)\n            created = True\n        return obj, created\n\n\n\n# Random, Unique\nclass Order(models.Model):\n    billing_profile     = models.ForeignKey(BillingProfile, null=True, blank=True)\n    order_id            = models.CharField(max_length=120, blank=True) # AB31DE3\n    shipping_address    = models.ForeignKey(Address, related_name=\"shipping_address\",null=True, blank=True)\n    billing_address     = models.ForeignKey(Address, related_name=\"billing_address\", null=True, blank=True)\n    shipping_address_final    = models.TextField(blank=True, null=True)\n    billing_address_final     = models.TextField(blank=True, null=True)\n    cart                = models.ForeignKey(Cart)\n    status              = models.CharField(max_length=120, default='created', choices=ORDER_STATUS_CHOICES)\n    shipping_total      = models.DecimalField(default=5.99, max_digits=100, decimal_places=2)\n    total               = models.DecimalField(default=0.00, max_digits=100, decimal_places=2)\n    active              = models.BooleanField(default=True)\n    updated             = models.DateTimeField(auto_now=True)\n    timestamp           = models.DateTimeField(auto_now_add=True)\n\n    def __str__(self):\n        return self.order_id\n\n    objects = OrderManager()\n\n    class Meta:\n       ordering = ['-timestamp', '-updated']\n\n    def get_absolute_url(self):\n        return reverse(\"orders:detail\", kwargs={'order_id': self.order_id})\n\n    def get_status(self):\n        if self.status == \"refunded\":\n            return \"Refunded order\"\n        elif self.status == \"shipped\":\n            return \"Shipped\"\n        return \"Shipping Soon\"\n\n    def update_total(self):\n        cart_total = self.cart.total\n        shipping_total = self.shipping_total\n        new_total = math.fsum([cart_total, shipping_total])\n        formatted_total = format(new_total, '.2f')\n        self.total = formatted_total\n        self.save()\n        return new_total\n\n    def check_done(self):\n        shipping_address_required = not self.cart.is_digital\n        shipping_done = False\n        if shipping_address_required and self.shipping_address:\n            shipping_done = True\n        elif shipping_address_required and not self.shipping_address:\n            shipping_done = False\n        else:\n            shipping_done = True\n        billing_profile = self.billing_profile\n        billing_address = self.billing_address\n        total   = self.total\n        if billing_profile and shipping_done and billing_address and total > 0:\n            return True\n        return False\n\n    def update_purchases(self):\n        for p in self.cart.products.all():\n            obj, created = ProductPurchase.objects.get_or_create(\n                    order_id=self.order_id,\n                    product=p,\n                    billing_profile=self.billing_profile\n                )\n        return ProductPurchase.objects.filter(order_id=self.order_id).count()\n\n    def mark_paid(self):\n        if self.status != 'paid':\n            if self.check_done():\n                self.status = \"paid\"\n                self.save()\n                self.update_purchases()\n        return self.status\n\n\ndef pre_save_create_order_id(sender, instance, *args, **kwargs):\n    if not instance.order_id:\n        instance.order_id = unique_order_id_generator(instance)\n    qs = Order.objects.filter(cart=instance.cart).exclude(billing_profile=instance.billing_profile)\n    if qs.exists():\n        qs.update(active=False)\n\n    if instance.shipping_address and not instance.shipping_address_final:\n        instance.shipping_address_final = instance.shipping_address.get_address()\n\n    if instance.billing_address and not instance.billing_address_final:\n        instance.billing_address_final = instance.billing_address.get_address()\n\n\npre_save.connect(pre_save_create_order_id, sender=Order)\n\n\ndef post_save_cart_total(sender, instance, created, *args, **kwargs):\n    if not created:\n        cart_obj = instance\n        cart_total = cart_obj.total\n        cart_id = cart_obj.id\n        qs = Order.objects.filter(cart__id=cart_id)\n        if qs.count() == 1:\n            order_obj = qs.first()\n            order_obj.update_total()\n\npost_save.connect(post_save_cart_total, sender=Cart)\n\n\ndef post_save_order(sender, instance, created, *args, **kwargs):\n    #print(\"running\")\n    if created:\n        print(\"Updating... first\")\n        instance.update_total()\n\n\npost_save.connect(post_save_order, sender=Order)\n\n\n\nclass ProductPurchaseQuerySet(models.query.QuerySet):\n    def active(self):\n        return self.filter(refunded=False)\n\n    def digital(self):\n        return self.filter(product__is_digital=True)\n\n    def by_request(self, request):\n        billing_profile, created = BillingProfile.objects.new_or_get(request)\n        return self.filter(billing_profile=billing_profile)\n\n\n\nclass ProductPurchaseManager(models.Manager):\n    def get_queryset(self):\n        return ProductPurchaseQuerySet(self.model, using=self._db)\n\n    def all(self):\n        return self.get_queryset().active()\n\n    def digital(self):\n        return self.get_queryset().active().digital()\n\n    def by_request(self, request):\n        return self.get_queryset().by_request(request)\n\n    def products_by_id(self, request):\n        qs = self.by_request(request).digital()\n        ids_ = [x.product.id for x in qs]\n        return ids_\n\n    def products_by_request(self, request):\n        ids_ = self.products_by_id(request)\n        products_qs = Product.objects.filter(id__in=ids_).distinct()\n        return products_qs\n\n\n\nclass ProductPurchase(models.Model):\n    order_id            = models.CharField(max_length=120)\n    billing_profile     = models.ForeignKey(BillingProfile) # billingprofile.productpurchase_set.all()\n    product             = models.ForeignKey(Product) # product.productpurchase_set.count()\n    refunded            = models.BooleanField(default=False)\n    updated             = models.DateTimeField(auto_now=True)\n    timestamp           = models.DateTimeField(auto_now_add=True)\n\n    objects = ProductPurchaseManager()\n\n    def __str__(self):\n        return self.product.title\n\n\n\n\n\n"
  },
  {
    "path": "src/orders/templates/orders/library.html",
    "content": "{% extends \"base.html\" %}\n\n\n{% block content %}\n\n\n<div class='row'>\n    <div class='col-12'>\n        <h1>Library</h1>\n    </div>\n</div>\n<div class='row'>\n    <div class='col'>\n        <table class='table'>\n            <thead><th>Product</th><th>Download</th></thead>\n\n            <tbody>\n                {% for object in object_list %}\n                    <tr>\n                        <td><a href='{{ object.get_absolute_url }}'>{{ object.title }}</a></td>\n                        <td>{% for download in object.get_downloads %}\n                                <a href='{{ download.get_download_url }}'>{{ download.display_name }}</a><br/>\n                            {% endfor %}\n                        </td>\n                    </tr>\n                {% empty %}\n                <tr><td colspan=\"3\"><p class='lead'>No orders yet.</td></tr>\n                {% endfor %}\n            </tbody>\n\n        </table>\n    </div>\n</div>\n\n\n\n{% endblock %}"
  },
  {
    "path": "src/orders/templates/orders/order_detail.html",
    "content": "{% extends \"base.html\" %}\n\n\n{% block content %}\n\n\n\n\n\n <div class='row'>\n    <div class='col-12 col-md-6 mx-auto'>\n         <h1>Order {{ object.order_id }}</h1>\n          <hr/>\n    </div>\n</div>\n\n<div class='row'>\n    <div class='col-12 col-md-6 mx-auto'>\n<p>Items: {% for product in object.cart.products.all %}{{ product }}{% if not forloop.last %}, {% endif %}{% endfor %}</p>\n<p>Shipping Address: {{ object.shipping_address_final }}</p>\n<p>Billing Address: {{ object.billing_address_final }}</p>\n<p>Subtotal: {{ object.cart.total }}</p>\n<p>Shipping Total: {{ object.shipping_total }}</p>\n<p>Order Total: {{ object.total }}</p>\n<p>Order Status: {{ object.get_status }}</p>\n</div>\n\n\n{% endblock %}"
  },
  {
    "path": "src/orders/templates/orders/order_list.html",
    "content": "{% extends \"base.html\" %}\n\n\n{% block content %}\n\n\n<div class='row'>\n    <div class='col-12'>\n        <h1>Orders</h1>\n    </div>\n</div>\n<div class='row'>\n    <div class='col'>\n        <table class='table'>\n            <thead><th>Order Id</th><th>Status</th><th>Total</th></thead>\n\n            <tbody>\n                {% for object in object_list %}\n                    <tr>\n                        <td><a href='{{ object.get_absolute_url }}'>{{ object.order_id }}</a></td>\n                        <td>{{ object.get_status }}</td>\n                        <td>{{ object.total }}</td>\n                    </tr>\n                {% empty %}\n                <tr><td colspan=\"3\"><p class='lead'>No orders yet.</td></tr>\n                {% endfor %}\n            </tbody>\n\n        </table>\n    </div>\n</div>\n\n\n\n{% endblock %}"
  },
  {
    "path": "src/orders/tests.py",
    "content": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "src/orders/urls.py",
    "content": "from django.conf.urls import url\n\nfrom .views import (\n        OrderListView, \n        OrderDetailView,\n        VerifyOwnership\n        )\n\nurlpatterns = [\n    url(r'^$', OrderListView.as_view(), name='list'),\n    url(r'^endpoint/verify/ownership/$', VerifyOwnership.as_view(), name='verify-ownership'),\n    url(r'^(?P<order_id>[0-9A-Za-z]+)/$', OrderDetailView.as_view(), name='detail'),\n]"
  },
  {
    "path": "src/orders/views.py",
    "content": "from django.contrib.auth.mixins import LoginRequiredMixin\nfrom django.http import Http404, JsonResponse\nfrom django.views.generic import View, ListView, DetailView\nfrom django.shortcuts import render\n\nfrom billing.models import BillingProfile\nfrom .models import Order, ProductPurchase\n\n\nclass OrderListView(LoginRequiredMixin, ListView):\n\n    def get_queryset(self):\n        return Order.objects.by_request(self.request).not_created()\n\n\nclass OrderDetailView(LoginRequiredMixin, DetailView):\n    \n    def get_object(self):\n        #return Order.objects.get(id=self.kwargs.get('id'))\n        #return Order.objects.get(slug=self.kwargs.get('slug'))\n        qs = Order.objects.by_request(\n                    self.request\n                ).filter(\n                    order_id = self.kwargs.get('order_id')\n                )\n        if qs.count() == 1:\n            return qs.first()\n        raise Http404\n\n\n\nclass LibraryView(LoginRequiredMixin, ListView):\n    template_name = 'orders/library.html'\n    def get_queryset(self):\n        return ProductPurchase.objects.products_by_request(self.request) #.by_request(self.request).digital()\n\n\nclass VerifyOwnership(View):\n    def get(self, request, *args, **kwargs):\n        if request.is_ajax():\n            data = request.GET \n            product_id = request.GET.get('product_id', None)\n            if product_id is not None:\n                product_id = int(product_id)\n                ownership_ids = ProductPurchase.objects.products_by_id(request)\n                if product_id in ownership_ids:\n                    return JsonResponse({'owner': True})\n            return JsonResponse({'owner': False})\n        raise Http404\n\n\n\n\n"
  },
  {
    "path": "src/products/__init__.py",
    "content": ""
  },
  {
    "path": "src/products/admin.py",
    "content": "from django.contrib import admin\n\nfrom .models import Product, ProductFile\n\n\nclass ProductFileInline(admin.TabularInline):\n    model = ProductFile\n    extra = 1\n\n\nclass ProductAdmin(admin.ModelAdmin):\n    list_display = ['__str__', 'slug', 'is_digital']\n    inlines = [ProductFileInline]\n    class Meta:\n        model = Product\n\nadmin.site.register(Product, ProductAdmin)"
  },
  {
    "path": "src/products/apps.py",
    "content": "from django.apps import AppConfig\n\n\nclass ProductsConfig(AppConfig):\n    name = 'products'\n"
  },
  {
    "path": "src/products/fixtures/products.json",
    "content": "[\n{\n    \"model\": \"products.product\",\n    \"pk\": 1,\n    \"fields\": {\n        \"title\": \"T-Shirt\",\n        \"slug\": \"t-shirt\",\n        \"description\": \"This is an awesome shirt. Buy it. :)\",\n        \"price\": \"39.99\",\n        \"image\": \"\",\n        \"featured\": false,\n        \"active\": true,\n        \"timestamp\": \"2017-09-18T19:29:03.347Z\"\n    }\n},\n{\n    \"model\": \"products.product\",\n    \"pk\": 3,\n    \"fields\": {\n        \"title\": \"Hat\",\n        \"slug\": \"hat\",\n        \"description\": \"This is my awesome hat\",\n        \"price\": \"39.99\",\n        \"image\": \"products/2969889474/2969889474.jpg\",\n        \"featured\": false,\n        \"active\": true,\n        \"timestamp\": \"2017-09-18T19:29:03.347Z\"\n    }\n},\n{\n    \"model\": \"products.product\",\n    \"pk\": 4,\n    \"fields\": {\n        \"title\": \"Lorem Ipsum\",\n        \"slug\": \"lorem-ipsum\",\n        \"description\": \"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed hendrerit venenatis feugiat. Proin blandit odio nec sem dignissim, ac fermentum sapien ornare. Praesent libero sem, mattis id ultricies eu, convallis ac ligula. Nulla porta ornare felis, ac elementum ante dapibus eu. Proin vitae vulputate sapien. Integer interdum dolor ante, in imperdiet est elementum molestie. In eu dui placerat, egestas diam ac, ultrices dui. Vivamus tincidunt, dui faucibus feugiat eleifend, eros sapien mollis metus, finibus gravida arcu sapien eu libero. Donec a ipsum rutrum, fringilla metus eu, sodales nisl. Vivamus eu condimentum sapien, sit amet malesuada nibh. Phasellus blandit, elit ullamcorper facilisis pulvinar, leo nunc congue augue, mollis efficitur eros turpis quis leo.\\r\\n\\r\\nMauris rutrum nunc vel libero porta, ut feugiat turpis rhoncus. Vestibulum vel mauris mi. Ut vitae dolor a neque commodo tincidunt semper id augue. Proin vehicula ex justo, vitae aliquet ligula cursus luctus. Vivamus a euismod lorem. Ut lacinia commodo faucibus. Proin malesuada rutrum porttitor. Quisque ac enim quis dui sollicitudin laoreet. Vivamus velit dui, accumsan eget egestas a, pharetra a nibh. Suspendisse ornare nunc quis euismod commodo. Morbi fringilla mauris nec eros placerat tempor. Ut facilisis consectetur lorem, sed imperdiet nulla tristique ac. Duis tristique id odio ut ornare.\\r\\n\\r\\nAliquam dui orci, pulvinar sit amet nisi at, blandit ullamcorper libero. Maecenas pharetra diam quis eros mattis, eu rhoncus augue efficitur. Sed cursus nulla ut dolor molestie consectetur. Praesent faucibus dignissim pulvinar. Nulla hendrerit risus in mattis ultricies. Quisque vitae lacinia tellus, ut finibus metus. Donec velit enim, pretium vitae ante blandit, tempus auctor mauris. Donec mattis metus et nisi ullamcorper, non posuere sapien tincidunt. Phasellus molestie pharetra augue. Quisque eget arcu magna. Aliquam mollis tortor tellus, vitae tempus lectus aliquet non. Sed vulputate dolor elit, ac semper velit auctor ac.\\r\\n\\r\\nMauris laoreet libero libero, sed sodales turpis euismod et. Maecenas vehicula egestas diam, quis volutpat metus cursus id. Nunc faucibus convallis hendrerit. Integer porttitor elit nec magna dapibus, ac tempus neque lacinia. Donec vel purus quis sem viverra gravida. Maecenas gravida tempor odio, vitae aliquet est facilisis vel. Nam sodales, elit ut ornare iaculis, ipsum orci aliquet tellus, eget consequat enim felis auctor leo. Quisque a mi mauris. Duis euismod justo ut ipsum tincidunt tincidunt. Aliquam erat volutpat. Sed vitae auctor enim, mattis laoreet arcu. Ut finibus sit amet velit vulputate pellentesque. Mauris non facilisis arcu, vel ultrices leo. Etiam fermentum urna vitae eros fermentum, vitae tincidunt arcu tristique.\\r\\n\\r\\nAliquam luctus eu massa nec condimentum. Pellentesque augue eros, lacinia at tortor non, feugiat convallis nisi. Morbi volutpat sagittis sapien ut sollicitudin. Nulla iaculis rhoncus neque eget varius. Donec commodo ultricies blandit. Quisque turpis dui, tincidunt in eros eu, sagittis luctus risus. Suspendisse molestie sapien placerat velit laoreet, non consequat mauris eleifend. Cras condimentum fermentum lorem. Donec laoreet neque nibh, ut imperdiet dui ullamcorper quis. Vestibulum at turpis at risus porttitor bibendum et vel dolor.\\r\\n\\r\\nPraesent pretium imperdiet leo, eu auctor arcu congue nec. Maecenas feugiat mauris elit. Vivamus vel sollicitudin metus, ut tempus ligula. Suspendisse non aliquet justo. Proin scelerisque cursus metus, in placerat ligula dignissim et. Duis fermentum ante dolor, aliquet malesuada velit feugiat vel. Morbi et sem in elit luctus vehicula vitae a nunc. Fusce ex purus, suscipit ac accumsan sed, scelerisque vel purus. In hac habitasse platea dictumst. Pellentesque eget nulla ac dolor porttitor ultricies. Nam eleifend massa eget justo suscipit viverra. In vel ligula turpis. Vestibulum ultricies, nibh vitae condimentum finibus, odio felis condimentum ipsum, in finibus leo dolor id turpis. Vivamus laoreet libero sit amet pulvinar mattis.\\r\\n\\r\\nPellentesque scelerisque imperdiet dui ac lacinia. Vivamus mi quam, condimentum ac gravida vitae, commodo eget turpis. Cras iaculis diam in elementum scelerisque. Maecenas ultricies, est quis posuere tempus, risus libero consequat augue, quis rutrum urna nulla a mauris. Quisque eleifend aliquam consectetur. Nulla consequat blandit molestie. Nam id facilisis tellus. In eget sem ac tellus lobortis pellentesque sagittis ac tellus.\\r\\n\\r\\nMorbi a ipsum dolor. Donec augue ipsum, faucibus id mauris nec, bibendum pellentesque magna. Etiam eleifend urna vel libero accumsan consequat. Praesent molestie diam eu urna dignissim, et tristique felis rutrum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Praesent ante magna, ornare nec fermentum nec, dictum ut nunc. Donec sed nunc rutrum, sollicitudin dolor nec, cursus felis. Integer ut dui sed ligula placerat lobortis in ac felis.\\r\\n\\r\\nAenean pretium turpis et ornare egestas. Curabitur egestas, sapien vitae tempor interdum, ante nisl auctor elit, at dictum lectus turpis sit amet lacus. Pellentesque lorem odio, lacinia quis augue ultricies, tincidunt aliquet dui. Fusce blandit nunc id ullamcorper scelerisque. Nunc eget ornare mi. Donec ac odio suscipit, pharetra libero at, hendrerit leo. Duis feugiat sapien eget augue rutrum malesuada. In faucibus, dolor sed congue aliquet, sapien massa gravida ipsum, eu sagittis leo tortor in metus. Ut egestas vehicula mollis.\\r\\n\\r\\nNulla tempus mi ac mauris pellentesque, non pellentesque risus luctus. Maecenas non nibh euismod, vestibulum mauris sit amet, malesuada augue. Aenean ut egestas magna. Integer sagittis mattis faucibus. Nulla luctus nisi diam, sit amet euismod magna laoreet a. Ut vehicula nibh ut sem blandit, nec congue ligula cursus. Sed eget nulla at lorem finibus rutrum. Nunc sagittis sem in mattis sagittis. Fusce id tincidunt nibh. Fusce rutrum nisi at leo cursus, eget rhoncus nibh porttitor. Maecenas maximus a augue eu tempor.\\r\\n\\r\\nVivamus tristique interdum congue. Phasellus feugiat dui augue, et consectetur erat venenatis nec. Cras ut tempus metus. Sed vestibulum pulvinar odio, eget vehicula orci lobortis at. Nulla purus est, gravida sed libero in, sollicitudin aliquam ante. Mauris non nisi quis sapien laoreet gravida sed sit amet libero. Vestibulum lacinia porttitor felis, quis maximus tortor laoreet quis. Nulla consequat, est eu vestibulum convallis, eros nisi vehicula nibh, sed pulvinar felis risus vitae ex. Proin cursus congue ornare. Duis quis eleifend arcu. Maecenas dictum ligula at risus imperdiet condimentum. Phasellus malesuada neque non mollis auctor. Sed in ultricies risus, non porta ex.\\r\\n\\r\\nProin gravida tortor dictum accumsan venenatis. Pellentesque euismod nisl tortor. Nullam interdum felis ut nulla egestas vehicula. Phasellus enim diam, malesuada a nisl vel, pellentesque malesuada massa. Curabitur pellentesque feugiat lorem vel ultrices. Vestibulum felis nisi, semper in augue vitae, blandit feugiat purus. Duis dolor risus, rhoncus ac semper et, finibus a orci. Aliquam hendrerit ligula eget velit consequat tincidunt. Integer mollis sapien in lacus rutrum, ut efficitur dui ultrices. Phasellus ut risus placerat, accumsan massa id, rhoncus augue.\\r\\n\\r\\nDonec nisi felis, condimentum in viverra id, pharetra quis augue. Donec ac quam ut dui bibendum viverra. Vivamus vel justo sed elit euismod iaculis. Fusce molestie mattis libero sit amet sagittis. Integer a nisl eu massa porta dignissim. Phasellus lectus risus, sagittis eu lorem eu, elementum ullamcorper tellus. Proin sed orci sed dolor posuere dignissim. Quisque pulvinar purus eu neque pretium, vehicula elementum ligula elementum. Sed gravida consectetur augue, eget dignissim elit euismod a. Sed commodo pulvinar arcu, sit amet ornare tortor placerat venenatis.\\r\\n\\r\\nPhasellus in lobortis nulla. Morbi et neque erat. Nunc porta commodo odio, in elementum metus porttitor scelerisque. Vestibulum lacinia tristique lacus eget dictum. Donec in orci mi. Mauris semper sodales mi vitae pellentesque. Donec iaculis congue accumsan. Fusce ut rutrum ex, eget porta turpis. Suspendisse scelerisque ex nec risus fermentum, nec elementum nisl iaculis. Maecenas non leo lacus. Morbi lacinia tortor purus, vel aliquam lorem laoreet eget. Vivamus rhoncus congue urna, at finibus est sodales et. Morbi sodales lacus ut ante consequat, egestas placerat eros tincidunt. Pellentesque maximus ligula leo, sed dictum metus ultrices in.\\r\\n\\r\\nInteger sagittis sem non nisl suscipit, sed congue leo ultrices. Vestibulum consectetur interdum venenatis. Donec egestas feugiat erat sed molestie. Vestibulum eleifend lectus nec est dapibus, in egestas ante ultrices. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In iaculis sed sapien at feugiat. Integer enim dolor, iaculis vel tortor nec, fermentum dictum ligula. Cras ornare cursus magna, ut scelerisque mi pellentesque quis.\\r\\n\\r\\nMorbi pulvinar, arcu eget vestibulum congue, diam lorem tempus risus, at vehicula nibh dui eget massa. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Etiam aliquam velit dui, non aliquam nulla mattis ac. Suspendisse dapibus pharetra accumsan. Donec sem justo, ullamcorper id volutpat sit amet, placerat lobortis libero. Etiam vestibulum sagittis dui. Aliquam libero ipsum, dictum rhoncus nulla non, pellentesque aliquet mi. Vivamus sed porta ex. Nam finibus orci in porta semper. Donec tincidunt euismod urna et blandit. Vivamus lobortis placerat consectetur. Nullam porttitor, magna ut tincidunt tincidunt, nibh justo facilisis nulla, quis laoreet nisl mauris eu sem. Nunc a lobortis felis.\\r\\n\\r\\nInteger at mi sit amet magna venenatis imperdiet. Curabitur interdum quam sit amet urna fringilla, sed tristique velit posuere. Quisque hendrerit laoreet orci vitae rhoncus. Sed finibus, nibh sed hendrerit elementum, purus mi lobortis arcu, a fermentum nisl arcu id quam. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed fermentum erat eleifend risus accumsan faucibus. Fusce ultrices sollicitudin sem vel viverra. Suspendisse sodales ipsum eget ultrices accumsan. Pellentesque vel eros ante. Sed tristique egestas tincidunt. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.\\r\\n\\r\\nDonec blandit turpis non justo hendrerit tincidunt. Aliquam dolor metus, volutpat a laoreet vel, efficitur at metus. Nam venenatis sem dui, vitae tincidunt nulla venenatis sit amet. Curabitur tristique, dolor sed aliquet molestie, ex erat semper mi, in ornare nunc mauris ut justo. Integer iaculis sollicitudin magna, sit amet interdum sapien pharetra ut. Mauris aliquam congue eros, non pharetra mi imperdiet nec. Aliquam at porta risus, eu imperdiet ante. Nunc consectetur eu elit ut facilisis. Praesent sed neque risus. Nunc euismod eros mauris, eget congue elit volutpat ut. Nam sit amet neque massa.\\r\\n\\r\\nNam sit amet est vel sem sagittis varius. Cras ornare eu turpis vitae varius. Integer sit amet ex sed arcu semper consectetur. Proin ac libero iaculis, porttitor mi vel, accumsan lorem. Maecenas venenatis lobortis justo. Integer aliquet, elit nec faucibus euismod, quam purus suscipit lorem, sit amet sollicitudin nisl purus sit amet ex. Aenean ultrices libero a felis porttitor, id malesuada erat consectetur. Suspendisse velit nulla, egestas sit amet scelerisque eget, elementum eget lectus. Nullam at accumsan ipsum. In placerat, ante vitae scelerisque sollicitudin, dui nisi lobortis diam, eget maximus turpis arcu tristique est. Cras et nibh porta, hendrerit lorem ut, fringilla risus.\\r\\n\\r\\nQuisque eu nulla molestie, fermentum arcu nec, pharetra orci. Nulla molestie, neque ac ullamcorper aliquam, mauris lacus aliquam libero, at auctor diam justo sit amet eros. Integer vehicula, mauris sit amet aliquet elementum, libero urna commodo purus, quis commodo dolor orci id diam. Aliquam erat volutpat. Suspendisse quis suscipit libero. Aliquam placerat, dui nec vulputate auctor, mauris tortor fermentum felis, nec lacinia felis metus nec urna. Nulla vitae metus luctus erat fermentum consectetur. Nulla facilisi. Donec turpis ante, luctus vel turpis ut, rutrum sagittis urna. Quisque ut tellus ligula. Mauris eget magna lectus. Fusce at suscipit sapien. Praesent fringilla tincidunt ullamcorper. Duis id sollicitudin neque, sit amet rhoncus sem. Sed lacinia odio neque, nec lacinia ante dictum vitae. Nullam in suscipit augue.\\r\\n\\r\\nSed nulla lacus, sagittis quis purus eu, pulvinar tincidunt libero. Etiam sed elementum erat. Donec lacinia nulla sed justo pulvinar ultricies. Suspendisse lorem ante, placerat vitae facilisis sit amet, commodo ac velit. Etiam in sapien commodo, vestibulum augue ac, convallis enim. Aenean ut magna sapien. Praesent fermentum odio risus, imperdiet tempor libero sagittis non. Aliquam euismod bibendum nisi a suscipit. Morbi enim ex, varius vitae lacus et, sodales luctus elit. Phasellus et tellus velit.\\r\\n\\r\\nQuisque a nibh ac dolor congue congue. Mauris at tempus sapien. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce dapibus magna sit amet malesuada accumsan. Nullam velit leo, ultricies et interdum convallis, varius ut elit. Cras facilisis faucibus est, vitae tempor ex placerat a. In mattis vel nulla nec volutpat. Maecenas tristique sodales venenatis. In dapibus, urna sit amet aliquam rhoncus, mi neque ultricies dolor, in pretium leo metus quis lacus. Mauris non consectetur lacus, sit amet imperdiet mi. Morbi egestas urna vel enim fermentum, vitae vestibulum neque congue. Vivamus tempus ipsum iaculis congue placerat. Nunc odio quam, bibendum mattis molestie id, sollicitudin consectetur lacus. Cras sagittis pharetra nibh vel scelerisque. Aenean in erat pellentesque, tempus libero non, convallis dolor. Sed et lorem in sapien fermentum condimentum.\\r\\n\\r\\nCurabitur eu augue a risus elementum sollicitudin. Aliquam erat volutpat. Fusce porttitor pulvinar ipsum, vel ornare erat pharetra non. Aliquam et metus vitae mi sollicitudin tristique vel vitae nulla. Nullam lobortis arcu eu iaculis eleifend. Vivamus magna nibh, ultrices eu est efficitur, dictum molestie odio. Donec ullamcorper, metus eu hendrerit cursus, erat nulla convallis quam, et efficitur nisi eros eget erat. Sed id metus dui. Nulla facilisi. Nulla facilisi. Pellentesque dignissim venenatis iaculis. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.\\r\\n\\r\\nProin viverra, quam vitae egestas iaculis, tellus est consequat urna, vitae vehicula arcu dolor sit amet nulla. Phasellus sit amet purus eu lorem lacinia iaculis ac id mi. In sollicitudin urna in pellentesque rutrum. Sed efficitur felis at sagittis efficitur. Duis faucibus aliquet est, at commodo ipsum interdum sit amet. Cras eu libero hendrerit, elementum ex a, placerat ligula. Vestibulum nec orci ut metus blandit suscipit vel vel magna. Nulla facilisi. Integer porta rhoncus nulla vitae pharetra.\\r\\n\\r\\nMorbi lacinia nulla quis libero viverra efficitur. Sed nec magna in mauris eleifend rutrum ac nec augue. Aliquam accumsan gravida aliquam. Curabitur vel diam at neque luctus hendrerit eget non lacus. In nec ligula lorem. Mauris eget urna rhoncus, hendrerit sapien ut, sagittis urna. Etiam porta, lacus id auctor mattis, nulla diam euismod mauris, vitae fermentum nulla dolor id eros. Pellentesque convallis tellus velit, sed porta augue tincidunt at. Sed efficitur leo quis sapien lobortis aliquam. Aenean ac bibendum felis. Nulla lectus elit, dapibus nec fringilla nec, lacinia sit amet eros. Fusce egestas ipsum felis, id gravida orci dapibus consectetur. Vestibulum sed ultrices metus.\\r\\n\\r\\nCurabitur a euismod justo, eget vehicula augue. Morbi at aliquam augue, vitae auctor orci. Nam dignissim posuere nunc a euismod. Nunc iaculis dui ut justo vulputate euismod. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Suspendisse sodales mi non egestas sollicitudin. Mauris ultricies leo libero, non tincidunt libero sollicitudin non. Morbi dictum eget purus quis placerat. Vestibulum consequat, ipsum molestie venenatis fringilla, orci ex luctus elit, quis bibendum tortor ante a ligula. Nulla at leo rutrum, accumsan diam sed, consectetur ligula. Donec dignissim vitae elit at finibus. Vivamus a euismod lacus. Donec in euismod erat. Quisque tempor augue eleifend, dignissim enim ut, ultrices est. Nulla lacinia pretium augue non lacinia. Aenean auctor odio ac risus elementum tempor.\\r\\n\\r\\nCurabitur aliquam orci elit, id consequat nunc consequat quis. Duis sed elit vel magna aliquam convallis. Praesent viverra vel urna vel luctus. Maecenas cursus elit eu suscipit aliquet. Pellentesque sit amet lorem vel erat luctus vestibulum. Proin rhoncus leo a dui ullamcorper consectetur. Curabitur vel nunc nec enim mollis dictum sit amet sit amet lorem. Aliquam pharetra non magna sed viverra.\\r\\n\\r\\nUt eu lorem in purus aliquet lacinia at non nulla. Ut auctor interdum nisi, nec aliquam ligula viverra nec. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Pellentesque posuere lacus arcu. Sed ipsum orci, tempor quis eleifend a, hendrerit et augue. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Etiam turpis dolor, rhoncus ac aliquam et, maximus ac libero. Vestibulum sollicitudin, eros in iaculis posuere, ante ante vulputate leo, sed venenatis nisi felis eu augue. Donec in sapien non elit ultrices viverra ac at nibh. Vestibulum sagittis rutrum turpis nec luctus. Aliquam sit amet urna ipsum. Sed ornare condimentum ipsum nec bibendum.\\r\\n\\r\\nMaecenas et tempor nisi. Sed eleifend lacus sit amet feugiat vestibulum. Vestibulum condimentum lacus vel leo finibus luctus. Maecenas urna dui, feugiat vehicula nibh vitae, gravida consequat tortor. Sed vitae orci vel lacus efficitur accumsan. Aenean tincidunt ligula a nibh pretium, quis viverra nunc laoreet. Cras varius sapien ac nunc vulputate dictum et id lorem. Ut in ante pretium, finibus enim a, malesuada lectus. Curabitur eu nisl venenatis, efficitur tellus vel, tincidunt velit. Aliquam a sem mattis ipsum condimentum venenatis eu ut orci. Curabitur sed justo tristique, varius justo vel, laoreet est. Nullam at felis non lacus faucibus porttitor.\\r\\n\\r\\nDonec lobortis dictum hendrerit. Aliquam lacinia mattis ullamcorper. Pellentesque sollicitudin lorem magna, nec interdum leo porttitor non. Nunc risus tellus, commodo nec turpis eget, lacinia venenatis lectus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Mauris eleifend sapien et ullamcorper malesuada. Suspendisse blandit erat ac malesuada malesuada. Phasellus ullamcorper ullamcorper risus quis venenatis. Nulla rutrum nibh magna, a elementum justo ornare ut.\",\n        \"price\": \"99.99\",\n        \"image\": \"\",\n        \"featured\": true,\n        \"active\": true,\n        \"timestamp\": \"2017-09-18T19:29:03.347Z\"\n    }\n},\n{\n    \"model\": \"products.product\",\n    \"pk\": 5,\n    \"fields\": {\n        \"title\": \"T-shirt\",\n        \"slug\": \"t-shirt-y7f6\",\n        \"description\": \"another one?>?\",\n        \"price\": \"39.99\",\n        \"image\": \"\",\n        \"featured\": false,\n        \"active\": true,\n        \"timestamp\": \"2017-09-18T19:29:03.347Z\"\n    }\n}\n]\n"
  },
  {
    "path": "src/products/migrations/0001_initial.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-01 19:03\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    initial = True\n\n    dependencies = [\n    ]\n\n    operations = [\n        migrations.CreateModel(\n            name='Product',\n            fields=[\n                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),\n                ('title', models.CharField(max_length=120)),\n                ('description', models.TextField()),\n            ],\n        ),\n    ]\n"
  },
  {
    "path": "src/products/migrations/0002_product_price.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-01 19:07\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('products', '0001_initial'),\n    ]\n\n    operations = [\n        migrations.AddField(\n            model_name='product',\n            name='price',\n            field=models.DecimalField(decimal_places=2, default=39.99, max_digits=20),\n        ),\n    ]\n"
  },
  {
    "path": "src/products/migrations/0003_product_image.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-01 21:48\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('products', '0002_product_price'),\n    ]\n\n    operations = [\n        migrations.AddField(\n            model_name='product',\n            name='image',\n            field=models.FileField(blank=True, null=True, upload_to='products/'),\n        ),\n    ]\n"
  },
  {
    "path": "src/products/migrations/0004_auto_20170901_2159.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-01 21:59\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\nimport products.models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('products', '0003_product_image'),\n    ]\n\n    operations = [\n        migrations.AlterField(\n            model_name='product',\n            name='image',\n            field=models.ImageField(blank=True, null=True, upload_to=products.models.upload_image_path),\n        ),\n    ]\n"
  },
  {
    "path": "src/products/migrations/0005_product_featured.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-01 22:39\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('products', '0004_auto_20170901_2159'),\n    ]\n\n    operations = [\n        migrations.AddField(\n            model_name='product',\n            name='featured',\n            field=models.BooleanField(default=False),\n        ),\n    ]\n"
  },
  {
    "path": "src/products/migrations/0006_auto_20170901_2254.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-01 22:54\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('products', '0005_product_featured'),\n    ]\n\n    operations = [\n        migrations.AddField(\n            model_name='product',\n            name='active',\n            field=models.BooleanField(default=True),\n        ),\n        migrations.AddField(\n            model_name='product',\n            name='slug',\n            field=models.SlugField(default='abc'),\n            preserve_default=False,\n        ),\n    ]\n"
  },
  {
    "path": "src/products/migrations/0007_auto_20170901_2254.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-01 22:54\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('products', '0006_auto_20170901_2254'),\n    ]\n\n    operations = [\n        migrations.AlterField(\n            model_name='product',\n            name='slug',\n            field=models.SlugField(blank=True),\n        ),\n    ]\n"
  },
  {
    "path": "src/products/migrations/0008_auto_20170901_2300.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-01 23:00\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('products', '0007_auto_20170901_2254'),\n    ]\n\n    operations = [\n        migrations.AlterField(\n            model_name='product',\n            name='slug',\n            field=models.SlugField(blank=True, unique=True),\n        ),\n    ]\n"
  },
  {
    "path": "src/products/migrations/0009_product_timestamp.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-18 19:28\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\nimport django.utils.timezone\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('products', '0008_auto_20170901_2300'),\n    ]\n\n    operations = [\n        migrations.AddField(\n            model_name='product',\n            name='timestamp',\n            field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),\n            preserve_default=False,\n        ),\n    ]\n"
  },
  {
    "path": "src/products/migrations/0010_product_is_digital.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-11-07 22:47\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('products', '0009_product_timestamp'),\n    ]\n\n    operations = [\n        migrations.AddField(\n            model_name='product',\n            name='is_digital',\n            field=models.BooleanField(default=False),\n        ),\n    ]\n"
  },
  {
    "path": "src/products/migrations/0011_productfile.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-11-08 23:07\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\nimport django.db.models.deletion\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('products', '0010_product_is_digital'),\n    ]\n\n    operations = [\n        migrations.CreateModel(\n            name='ProductFile',\n            fields=[\n                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),\n                ('file', models.FileField(upload_to='products/')),\n                ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='products.Product')),\n            ],\n        ),\n    ]\n"
  },
  {
    "path": "src/products/migrations/0012_auto_20171108_2325.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-11-08 23:25\nfrom __future__ import unicode_literals\n\nimport django.core.files.storage\nfrom django.db import migrations, models\nimport products.models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('products', '0011_productfile'),\n    ]\n\n    operations = [\n        migrations.AlterField(\n            model_name='productfile',\n            name='file',\n            field=models.FileField(storage=django.core.files.storage.FileSystemStorage(location='/Users/cfe/Dev/ecommerce/static_cdn/protected_media'), upload_to=products.models.upload_product_file_loc),\n        ),\n    ]\n"
  },
  {
    "path": "src/products/migrations/0013_auto_20171109_0023.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-11-09 00:23\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('products', '0012_auto_20171108_2325'),\n    ]\n\n    operations = [\n        migrations.AddField(\n            model_name='productfile',\n            name='free',\n            field=models.BooleanField(default=False),\n        ),\n        migrations.AddField(\n            model_name='productfile',\n            name='user_required',\n            field=models.BooleanField(default=False),\n        ),\n    ]\n"
  },
  {
    "path": "src/products/migrations/0014_auto_20171116_0011.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-11-16 00:11\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\nimport products.models\nimport storages.backends.s3boto3\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('products', '0013_auto_20171109_0023'),\n    ]\n\n    operations = [\n        migrations.AlterField(\n            model_name='productfile',\n            name='file',\n            field=models.FileField(storage=storages.backends.s3boto3.S3Boto3Storage(location='protected'), upload_to=products.models.upload_product_file_loc),\n        ),\n    ]\n"
  },
  {
    "path": "src/products/migrations/0015_productfile_name.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-11-16 00:12\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('products', '0014_auto_20171116_0011'),\n    ]\n\n    operations = [\n        migrations.AddField(\n            model_name='productfile',\n            name='name',\n            field=models.CharField(blank=True, max_length=120, null=True),\n        ),\n    ]\n"
  },
  {
    "path": "src/products/migrations/__init__.py",
    "content": ""
  },
  {
    "path": "src/products/models.py",
    "content": "import random\nimport os\nfrom django.conf import settings\nfrom django.core.files.storage import FileSystemStorage\n\nfrom django.db import models\nfrom django.db.models import Q\nfrom django.db.models.signals import pre_save, post_save\nfrom django.urls import reverse\n\nfrom ecommerce.aws.download.utils import AWSDownload\nfrom ecommerce.aws.utils import ProtectedS3Storage\nfrom ecommerce.utils import unique_slug_generator, get_filename\n\ndef get_filename_ext(filepath):\n    base_name = os.path.basename(filepath)\n    name, ext = os.path.splitext(base_name)\n    return name, ext\n\n\ndef upload_image_path(instance, filename):\n    # print(instance)\n    #print(filename)\n    new_filename = random.randint(1,3910209312)\n    name, ext = get_filename_ext(filename)\n    final_filename = '{new_filename}{ext}'.format(new_filename=new_filename, ext=ext)\n    return \"products/{new_filename}/{final_filename}\".format(\n            new_filename=new_filename, \n            final_filename=final_filename\n            )\n\nclass ProductQuerySet(models.query.QuerySet):\n    def active(self):\n        return self.filter(active=True)\n\n    def featured(self):\n        return self.filter(featured=True, active=True)\n\n    def search(self, query):\n        lookups = (Q(title__icontains=query) | \n                  Q(description__icontains=query) |\n                  Q(price__icontains=query) |\n                  Q(tag__title__icontains=query)\n                  )\n        # tshirt, t-shirt, t shirt, red, green, blue,\n        return self.filter(lookups).distinct()\n\nclass ProductManager(models.Manager):\n    def get_queryset(self):\n        return ProductQuerySet(self.model, using=self._db)\n\n    def all(self):\n        return self.get_queryset().active()\n\n    def featured(self): #Product.objects.featured() \n        return self.get_queryset().featured()\n\n    def get_by_id(self, id):\n        qs = self.get_queryset().filter(id=id) # Product.objects == self.get_queryset()\n        if qs.count() == 1:\n            return qs.first()\n        return None\n\n    def search(self, query):\n        return self.get_queryset().active().search(query)\n\n\nclass Product(models.Model):\n    title           = models.CharField(max_length=120)\n    slug            = models.SlugField(blank=True, unique=True)\n    description     = models.TextField()\n    price           = models.DecimalField(decimal_places=2, max_digits=20, default=39.99)\n    image           = models.ImageField(upload_to=upload_image_path, null=True, blank=True)\n    featured        = models.BooleanField(default=False)\n    active          = models.BooleanField(default=True)\n    timestamp       = models.DateTimeField(auto_now_add=True)\n    is_digital      = models.BooleanField(default=False) # User Library\n\n    objects = ProductManager()\n\n    def get_absolute_url(self):\n        #return \"/products/{slug}/\".format(slug=self.slug)\n        return reverse(\"products:detail\", kwargs={\"slug\": self.slug})\n\n    def __str__(self):\n        return self.title\n\n    def __unicode__(self):\n        return self.title\n\n    @property\n    def name(self):\n        return self.title\n\n    def get_downloads(self):\n        qs = self.productfile_set.all()\n        return qs\n\n\ndef product_pre_save_receiver(sender, instance, *args, **kwargs):\n    if not instance.slug:\n        instance.slug = unique_slug_generator(instance)\n\npre_save.connect(product_pre_save_receiver, sender=Product) \n\n\ndef upload_product_file_loc(instance, filename):\n    slug = instance.product.slug\n    #id_ = 0\n    id_ = instance.id\n    if id_ is None:\n        Klass = instance.__class__\n        qs = Klass.objects.all().order_by('-pk')\n        if qs.exists():\n            id_ = qs.first().id + 1\n        else:\n            id_ = 0\n    if not slug:\n        slug = unique_slug_generator(instance.product)\n    location = \"product/{slug}/{id}/\".format(slug=slug, id=id_)\n    return location + filename #\"path/to/filename.mp4\"\n\n\n\nclass ProductFile(models.Model):\n    product         = models.ForeignKey(Product)\n    name            = models.CharField(max_length=120, null=True, blank=True)\n    file            = models.FileField(\n                        upload_to=upload_product_file_loc, \n                        storage=ProtectedS3Storage(), #FileSystemStorage(location=settings.PROTECTED_ROOT)\n                        ) # path\n    #filepath        = models.TextField() # '/protected/path/to/the/file/myfile.mp3'\n    free            = models.BooleanField(default=False) # purchase required\n    user_required   = models.BooleanField(default=False) # user doesn't matter\n\n\n    def __str__(self):\n        return str(self.file.name)\n\n    @property\n    def display_name(self):\n        og_name = get_filename(self.file.name)\n        if self.name:\n            return self.name\n        return og_name\n\n    def get_default_url(self):\n        return self.product.get_absolute_url()\n\n    def generate_download_url(self):\n        bucket = getattr(settings, 'AWS_STORAGE_BUCKET_NAME')\n        region = getattr(settings, 'S3DIRECT_REGION')\n        access_key = getattr(settings, 'AWS_ACCESS_KEY_ID')\n        secret_key = getattr(settings, 'AWS_SECRET_ACCESS_KEY')\n        if not secret_key or not access_key or not bucket or not region:\n            return \"/product-not-found/\"\n        PROTECTED_DIR_NAME = getattr(settings, 'PROTECTED_DIR_NAME', 'protected')\n        path = \"{base}/{file_path}\".format(base=PROTECTED_DIR_NAME, file_path=str(self.file))\n        aws_dl_object =  AWSDownload(access_key, secret_key, bucket, region)\n        file_url = aws_dl_object.generate_url(path, new_filename=self.display_name)\n        return file_url\n\n    def get_download_url(self): # detail view\n        return reverse(\"products:download\", \n                    kwargs={\"slug\": self.product.slug, \"pk\": self.pk}\n                )\n\n\n\n\n\n\n"
  },
  {
    "path": "src/products/templates/products/detail.html",
    "content": "{% extends \"base.html\" %}\n\n\n{% block content %}\n\n\n    <div class='row'>\n        <div class='col-12 col-md-6'>\n                <h1>{{ object.title }}</h1>\n                {{ object.timestamp|timesince }} ago\n                {{ object.description|linebreaks }}<br/>\n                {% if object.image %}\n                    <img src='{{ object.image.url }}' class='img-fluid' />\n                {% endif %}\n        </div>\n        <div class='col-12 col-md-6'>\n            {% include 'products/snippets/update-cart.html' with product=object cart=cart %}\n\n        </div>\n</div>\n\n\n{% endblock %}\n"
  },
  {
    "path": "src/products/templates/products/featured-detail.html",
    "content": "{{ object.title }} <br/>\n{{ object.description }} <br/>\n{% if object.image %}\n    <img src='{{ object.image.url }}' class='img-fluid' />\n{% endif %}"
  },
  {
    "path": "src/products/templates/products/list.html",
    "content": "{% extends \"base.html\" %}\n\n{% block content %}\n        <div class='row'>\n\n    {% for obj in object_list %}\n        <div class='col my-3'>\n        {% include 'products/snippets/card.html' with instance=obj %}  \n        \n        </div>\n    {% endfor %}\n</div>\n{% endblock %}"
  },
  {
    "path": "src/products/templates/products/snippets/card.html",
    "content": "<div class=\"card\" style=\"width: 20rem;\">\n  {% if instance.image %}\n    <a href=\"{{ instance.get_absolute_url }}\"><img class=\"card-img-top\" src=\"{{ instance.image.url }}\" alt=\"{{ instance.title}} logo\"></a>\n    {% endif %}\n  <div class=\"card-body\">\n    <h4 class=\"card-title\">{{ instance.title }}</h4>\n    <p class=\"card-text\">{{ instance.description|linebreaks|truncatewords:14 }}</p>\n    \n    <div class='text-center'>\n        <a href=\"{{ instance.get_absolute_url }}\" class=\"btn btn-primary my-2\">View</a>\n        {% include 'products/snippets/update-cart.html' with product=instance cart=cart %}\n    </div>\n   <!--  <a href=\"{% url 'products:detail' slug=instance.slug  %}\" class=\"btn btn-warning\">URL shortcut</a> -->\n  </div>\n</div>"
  },
  {
    "path": "src/products/templates/products/snippets/update-cart.html",
    "content": "<form class='form-product-ajax' method='POST' action='{% url \"cart:update\" %}' data-endpoint='{% url \"cart:update\" %}' class=\"form\" {% if request.user.is_authenticated %}data-user='abc'{% endif %}> {% csrf_token %}\n    <input type='hidden' name='product_id' value='{{ product.id }}' {% if  product.is_digital %}data-is-digital='true'{% endif%}/>\n      <span class='submit-span'>\n    {% if product in cart.products.all %}\n        <div class='btn-group'> <a class='btn btn-link' href='/cart/'>In cart</a> <button type='submit' class='btn btn-link'>Remove?</button></div>\n    {% else %}\n        <button type='submit'  class='btn btn-success'>Add to cart</button>\n    {% endif %}\n    </span>\n</form>"
  },
  {
    "path": "src/products/templates/products/user-history.html",
    "content": "{% extends \"base.html\" %}\n\n{% block content %}\n        <div class='row'>\n            <div class='col-12 my-3'>\n                    <h1>Product View History</h1>\n                    <hr/>\n            </div>\n    {% for obj in object_list %}\n        <div class='col'>\n        {{ forloop.counter }}\n        {% include 'products/snippets/card.html' with instance=obj.content_object %}  \n        </div>\n    {% endfor %}\n</div>\n{% endblock %}"
  },
  {
    "path": "src/products/tests.py",
    "content": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "src/products/understanding_crud.md",
    "content": "### Understanding CRUD\n\n\nCreate -- POST\nRetrieve / List / Search -- GET\nUpdate -- PUT / Patch / POST\nDelete -- Delete\n"
  },
  {
    "path": "src/products/urls.py",
    "content": "from django.conf.urls import url\n\nfrom .views import (\n        ProductListView, \n        ProductDetailSlugView, \n        ProductDownloadView\n        )\n\nurlpatterns = [\n    url(r'^$', ProductListView.as_view(), name='list'),\n    url(r'^(?P<slug>[\\w-]+)/$', ProductDetailSlugView.as_view(), name='detail'),\n    url(r'^(?P<slug>[\\w-]+)/(?P<pk>\\d+)/$', ProductDownloadView.as_view(), name='download'),\n]\n\n"
  },
  {
    "path": "src/products/views.py",
    "content": "# from django.views import ListView\nfrom django.contrib import messages\nfrom django.contrib.auth.mixins import LoginRequiredMixin\nfrom django.http import Http404, HttpResponse, HttpResponseRedirect\nfrom django.views.generic import ListView, DetailView, View\nfrom django.shortcuts import render, get_object_or_404, redirect\n\nfrom analytics.mixins import ObjectViewedMixin\n\nfrom carts.models import Cart\n\nfrom .models import Product, ProductFile\n\n\nclass ProductFeaturedListView(ListView):\n    template_name = \"products/list.html\"\n\n    def get_queryset(self, *args, **kwargs):\n        request = self.request\n        return Product.objects.all().featured()\n\n\nclass ProductFeaturedDetailView(ObjectViewedMixin, DetailView):\n    queryset = Product.objects.all().featured()\n    template_name = \"products/featured-detail.html\"\n\n    # def get_queryset(self, *args, **kwargs):\n    #     request = self.request\n    #     return Product.objects.featured()\n\n\nclass UserProductHistoryView(LoginRequiredMixin, ListView):\n    template_name = \"products/user-history.html\"\n    def get_context_data(self, *args, **kwargs):\n        context = super(UserProductHistoryView, self).get_context_data(*args, **kwargs)\n        cart_obj, new_obj = Cart.objects.new_or_get(self.request)\n        context['cart'] = cart_obj\n        return context\n\n    def get_queryset(self, *args, **kwargs):\n        request = self.request\n        views = request.user.objectviewed_set.by_model(Product, model_queryset=False)\n        return views\n\n\n\nclass ProductListView(ListView):\n    template_name = \"products/list.html\"\n\n    # def get_context_data(self, *args, **kwargs):\n    #     context = super(ProductListView, self).get_context_data(*args, **kwargs)\n    #     print(context)\n    #     return context\n\n    def get_context_data(self, *args, **kwargs):\n        context = super(ProductListView, self).get_context_data(*args, **kwargs)\n        cart_obj, new_obj = Cart.objects.new_or_get(self.request)\n        context['cart'] = cart_obj\n        return context\n\n    def get_queryset(self, *args, **kwargs):\n        request = self.request\n        return Product.objects.all()\n\n\ndef product_list_view(request):\n    queryset = Product.objects.all()\n    context = {\n        'object_list': queryset\n    }\n    return render(request, \"products/list.html\", context)\n\n\n\nclass ProductDetailSlugView(ObjectViewedMixin, DetailView):\n    queryset = Product.objects.all()\n    template_name = \"products/detail.html\"\n\n    def get_context_data(self, *args, **kwargs):\n        context = super(ProductDetailSlugView, self).get_context_data(*args, **kwargs)\n        cart_obj, new_obj = Cart.objects.new_or_get(self.request)\n        context['cart'] = cart_obj\n        return context\n\n    def get_object(self, *args, **kwargs):\n        request = self.request\n        slug = self.kwargs.get('slug')\n\n        #instance = get_object_or_404(Product, slug=slug, active=True)\n        try:\n            instance = Product.objects.get(slug=slug, active=True)\n        except Product.DoesNotExist:\n            raise Http404(\"Not found..\")\n        except Product.MultipleObjectsReturned:\n            qs = Product.objects.filter(slug=slug, active=True)\n            instance = qs.first()\n        except:\n            raise Http404(\"Uhhmmm \")\n        return instance\n\nimport os\nfrom wsgiref.util import FileWrapper # this used in django\nfrom mimetypes import guess_type\n\nfrom django.conf import settings\nfrom orders.models import ProductPurchase\n\nclass ProductDownloadView(View):\n    def get(self, request, *args, **kwargs):\n        slug = kwargs.get('slug')\n        pk = kwargs.get('pk')\n        downloads_qs = ProductFile.objects.filter(pk=pk, product__slug=slug)\n        if downloads_qs.count() != 1:\n            raise Http404(\"Download not found\")\n        download_obj = downloads_qs.first()\n        # permission checks\n        \n        can_download = False\n        user_ready  = True\n        if download_obj.user_required:\n            if not request.user.is_authenticated():\n                user_ready = False\n\n        purchased_products = Product.objects.none()\n        if download_obj.free:\n            can_download = True\n            user_ready = True\n        else:\n            # not free\n            purchased_products = ProductPurchase.objects.products_by_request(request)\n            if download_obj.product in purchased_products:\n                can_download = True\n        if not can_download or not user_ready:\n            messages.error(request, \"You do not have access to download this item\")\n            return redirect(download_obj.get_default_url())\n\n        aws_filepath = download_obj.generate_download_url()\n        print(aws_filepath)\n        return HttpResponseRedirect(aws_filepath)\n        # file_root = settings.PROTECTED_ROOT\n        # filepath = download_obj.file.path # .url /media/\n        # final_filepath = os.path.join(file_root, filepath) # where the file is stored\n        # with open(final_filepath, 'rb') as f:\n        #     wrapper = FileWrapper(f)\n        #     mimetype = 'application/force-download'\n        #     gussed_mimetype = guess_type(filepath)[0] # filename.mp4\n        #     if gussed_mimetype:\n        #         mimetype = gussed_mimetype\n        #     response = HttpResponse(wrapper, content_type=mimetype)\n        #     response['Content-Disposition'] = \"attachment;filename=%s\" %(download_obj.name)\n        #     response[\"X-SendFile\"] = str(download_obj.name)\n        #     return response\n        #return redirect(download_obj.get_default_url())\n\n\n\n\nclass ProductDetailView(ObjectViewedMixin, DetailView):\n    #queryset = Product.objects.all()\n    template_name = \"products/detail.html\"\n\n    def get_context_data(self, *args, **kwargs):\n        context = super(ProductDetailView, self).get_context_data(*args, **kwargs)\n        print(context)\n        # context['abc'] = 123\n        return context\n\n    def get_object(self, *args, **kwargs):\n        request = self.request\n        pk = self.kwargs.get('pk')\n        instance = Product.objects.get_by_id(pk)\n        if instance is None:\n            raise Http404(\"Product doesn't exist\")\n        return instance\n\n    # def get_queryset(self, *args, **kwargs):\n    #     request = self.request\n    #     pk = self.kwargs.get('pk')\n    #     return Product.objects.filter(pk=pk)\n\n\ndef product_detail_view(request, pk=None, *args, **kwargs):\n    # instance = Product.objects.get(pk=pk, featured=True) #id\n    # instance = get_object_or_404(Product, pk=pk, featured=True)\n    # try:\n    #     instance = Product.objects.get(id=pk)\n    # except Product.DoesNotExist:\n    #     print('no product here')\n    #     raise Http404(\"Product doesn't exist\")\n    # except:\n    #     print(\"huh?\")\n\n    instance = Product.objects.get_by_id(pk)\n    if instance is None:\n        raise Http404(\"Product doesn't exist\")\n    #print(instance)\n    # qs  = Product.objects.filter(id=pk)\n\n    # #print(qs)\n    # if qs.exists() and qs.count() == 1: # len(qs)\n    #     instance = qs.first()\n    # else:\n    #     raise Http404(\"Product doesn't exist\")\n\n    context = {\n        'object': instance\n    }\n    return render(request, \"products/detail.html\", context)\n"
  },
  {
    "path": "src/requirements.txt",
    "content": "boto3==1.4.7\nboto==2.48.0\nbotocore==1.7.32\ncertifi==2017.7.27.1\nchardet==3.0.4\ndj-database-url\ndjango-storages\ndjango==1.11.17\ndocutils==0.14\ngitdb2==2.0.3\ngitpython==2.1.7\ngunicorn==19.7.1\nidna==2.6\njmespath==0.9.3\nolefile==0.44\npillow\npip==9.0.1\npsycopg2-binary\npython-dateutil==2.6.1\npytz\nrequests>=2.20.0\ns3transfer==0.1.11\nsetuptools==36.6.0\nsix==1.11.0\nsmmap2==2.0.3\nstripe\nurllib3>=1.23\nwheel==0.30.0\n"
  },
  {
    "path": "src/runtime.txt",
    "content": "python-3.6.2"
  },
  {
    "path": "src/search/__init__.py",
    "content": ""
  },
  {
    "path": "src/search/admin.py",
    "content": "from django.contrib import admin\n\n# Register your models here.\n"
  },
  {
    "path": "src/search/apps.py",
    "content": "from django.apps import AppConfig\n\n\nclass SearchConfig(AppConfig):\n    name = 'search'\n"
  },
  {
    "path": "src/search/migrations/__init__.py",
    "content": ""
  },
  {
    "path": "src/search/models.py",
    "content": "from django.db import models\n\n# Create your models here.\n"
  },
  {
    "path": "src/search/templates/search/snippets/search-form.html",
    "content": "<form method='GET' action='{% url \"search:query\" %}' class=\"form my-2 my-lg-0 search-form\">\n  <div class='input-group'>\n    <input class=\"form-control\" type=\"text\" placeholder=\"Search\" name='q' aria-label=\"Search\" value='{{ request.GET.q }}'>\n    <span class='input-group-btn'>\n        <button class=\"btn btn-outline-success\" type=\"submit\">Search</button>\n    </span>\n    </div>\n</form>"
  },
  {
    "path": "src/search/templates/search/view.html",
    "content": "{% extends \"base.html\" %}\n\n{% block content %}\n <div class='row  mb-3'>\n            {% if query %}\n            <div class='col-12' >\n                Results for <b>{{ query }}</b>\n                <hr/>\n            </div>\n            {% else %}\n\n            <div class='col-12 col-md-6 mx-auto py-5'>\n               {% include 'search/snippets/search-form.html' %}\n\n            </div>\n            <div class='col-12'>\n                <hr>\n            </div>\n            {% endif %}\n</div>\n\n\n        <div class='row'>\n\n\n\n    {% for obj in object_list %}\n        <div class='col'>\n\n        {% include 'products/snippets/card.html' with instance=obj %}  \n        \n        {% if forloop.counter|divisibleby:3 %}\n         </div> </div><div class='row'><div class='col-12'><hr/></div>\n        {% elif forloop.counter|divisibleby:2 %}\n            </div> </div><div class='row'><div class='col-12'><hr/></div>\n        {% else %}\n         </div>  \n        {% endif %}\n       \n    \n    {% endfor %}\n</div>\n{% endblock %}"
  },
  {
    "path": "src/search/tests.py",
    "content": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "src/search/urls.py",
    "content": "from django.conf.urls import url\n\nfrom .views import (\n        SearchProductView\n        )\n\nurlpatterns = [\n    url(r'^$', SearchProductView.as_view(), name='query'),\n]\n\n"
  },
  {
    "path": "src/search/views.py",
    "content": "from django.shortcuts import render\nfrom django.views.generic import ListView\nfrom products.models import Product\n\nclass SearchProductView(ListView):\n    template_name = \"search/view.html\"\n\n    def get_context_data(self, *args, **kwargs):\n        context = super(SearchProductView, self).get_context_data(*args, **kwargs)\n        query = self.request.GET.get('q')\n        context['query'] = query\n        # SearchQuery.objects.create(query=query)\n        return context\n\n    def get_queryset(self, *args, **kwargs):\n        request = self.request\n        method_dict = request.GET\n        query = method_dict.get('q', None) # method_dict['q']\n        if query is not None:\n            return Product.objects.search(query)\n        return Product.objects.featured()\n        '''\n        __icontains = field contains this\n        __iexact = fields is exactly this\n        '''\n"
  },
  {
    "path": "src/static_my_proj/css/main.css",
    "content": "body {\n    color: #ccc;\n}"
  },
  {
    "path": "src/static_my_proj/css/stripe-custom-style.css",
    "content": "/**\n * The CSS shown here will not be introduced in the Quickstart guide, but shows\n * how you can use CSS to style your Element's container.\n */\n.StripeElement {\n  background-color: white;\n  padding: 8px 12px;\n  border-radius: 4px;\n  border: 1px solid transparent;\n  box-shadow: 0 1px 3px 0 #e6ebf1;\n  -webkit-transition: box-shadow 150ms ease;\n  transition: box-shadow 150ms ease;\n}\n\n.StripeElement--focus {\n  box-shadow: 0 1px 3px 0 #cfd7df;\n}\n\n.StripeElement--invalid {\n  border-color: #fa755a;\n}\n\n.StripeElement--webkit-autofill {\n  background-color: #fefde5 !important;\n}\n"
  },
  {
    "path": "src/static_my_proj/js/csrf.ajax.js",
    "content": "$(document).ready(function(){\n    // using jQuery\n    function getCookie(name) {\n        var cookieValue = null;\n        if (document.cookie && document.cookie !== '') {\n            var cookies = document.cookie.split(';');\n            for (var i = 0; i < cookies.length; i++) {\n                var cookie = jQuery.trim(cookies[i]);\n                // Does this cookie string begin with the name we want?\n                if (cookie.substring(0, name.length + 1) === (name + '=')) {\n                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));\n                    break;\n                }\n            }\n        }\n        return cookieValue;\n    }\n    var csrftoken = getCookie('csrftoken');\n\n    function csrfSafeMethod(method) {\n        // these HTTP methods do not require CSRF protection\n        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));\n    }\n    $.ajaxSetup({\n        beforeSend: function(xhr, settings) {\n            if (!csrfSafeMethod(settings.type) && !this.crossDomain) {\n                xhr.setRequestHeader(\"X-CSRFToken\", csrftoken);\n            }\n        }\n    });\n\n})"
  },
  {
    "path": "src/static_my_proj/js/ecommerce.js",
    "content": "$(document).ready(function(){\n    // Contact Form Handler\n\n    var contactForm = $(\".contact-form\")\n    var contactFormMethod = contactForm.attr(\"method\")\n    var contactFormEndpoint = contactForm.attr(\"action\") // /abc/\n    \n    \n    function displaySubmitting(submitBtn, defaultText, doSubmit){\n      if (doSubmit){\n        submitBtn.addClass(\"disabled\")\n        submitBtn.html(\"<i class='fa fa-spin fa-spinner'></i> Sending...\")\n      } else {\n        submitBtn.removeClass(\"disabled\")\n        submitBtn.html(defaultText)\n      }\n      \n    }\n\n\n    contactForm.submit(function(event){\n      event.preventDefault()\n\n      var contactFormSubmitBtn = contactForm.find(\"[type='submit']\")\n      var contactFormSubmitBtnTxt = contactFormSubmitBtn.text()\n\n\n      var contactFormData = contactForm.serialize()\n      var thisForm = $(this)\n      displaySubmitting(contactFormSubmitBtn, \"\", true)\n      $.ajax({\n        method: contactFormMethod,\n        url:  contactFormEndpoint,\n        data: contactFormData,\n        success: function(data){\n          contactForm[0].reset()\n          $.alert({\n            title: \"Success!\",\n            content: data.message,\n            theme: \"modern\",\n          })\n          setTimeout(function(){\n            displaySubmitting(contactFormSubmitBtn, contactFormSubmitBtnTxt, false)\n          }, 500)\n        },\n        error: function(error){\n          console.log(error.responseJSON)\n          var jsonData = error.responseJSON\n          var msg = \"\"\n\n          $.each(jsonData, function(key, value){ // key, value  array index / object\n            msg += key + \": \" + value[0].message + \"<br/>\"\n          })\n\n          $.alert({\n            title: \"Oops!\",\n            content: msg,\n            theme: \"modern\",\n          })\n\n          setTimeout(function(){\n            displaySubmitting(contactFormSubmitBtn, contactFormSubmitBtnTxt, false)\n          }, 500)\n\n        }\n      })\n    })\n\n\n\n\n    // Auto Search\n    var searchForm = $(\".search-form\")\n    var searchInput = searchForm.find(\"[name='q']\") // input name='q'\n    var typingTimer;\n    var typingInterval = 500 // .5 seconds\n    var searchBtn = searchForm.find(\"[type='submit']\")\n    searchInput.keyup(function(event){\n      // key released\n      clearTimeout(typingTimer)\n\n      typingTimer = setTimeout(perfomSearch, typingInterval)\n    })\n\n    searchInput.keydown(function(event){\n      // key pressed\n      clearTimeout(typingTimer)\n    })\n\n    function displaySearching(){\n      searchBtn.addClass(\"disabled\")\n      searchBtn.html(\"<i class='fa fa-spin fa-spinner'></i> Searching...\")\n    }\n\n    function perfomSearch(){\n      displaySearching()\n      var query = searchInput.val()\n      setTimeout(function(){\n        window.location.href='/search/?q=' + query\n      }, 1000)\n      \n    }\n\n\n  // Cart + Add Products \n  var productForm = $(\".form-product-ajax\") // #form-product-ajax\n\n  function getOwnedProduct(productId, submitSpan){\n    var actionEndpoint = '/orders/endpoint/verify/ownership/'\n    var httpMethod = 'GET'\n    var data = {\n      product_id: productId\n    }\n\n    var isOwner;\n    $.ajax({\n        url: actionEndpoint,\n        method: httpMethod,\n        data: data,\n        success: function(data){\n          console.log(data)\n          console.log(data.owner)\n          if (data.owner){\n            isOwner = true\n            submitSpan.html(\"<a class='btn btn-warning' href='/library/'>In Library</a>\")\n          } else {\n            isOwner = false\n          }\n        },\n        error: function(erorr){\n          console.log(error)\n\n        }\n    })\n    return isOwner\n    \n  }\n\n  $.each(productForm, function(index, object){\n    var $this = $(this)\n    var isUser = $this.attr(\"data-user\")\n    var submitSpan = $this.find(\".submit-span\")\n    var productInput = $this.find(\"[name='product_id']\")\n    var productId = productInput.attr(\"value\")\n    var productIsDigital = productInput.attr(\"data-is-digital\")\n    \n    if (productIsDigital && isUser){\n      var isOwned = getOwnedProduct(productId, submitSpan)\n    }\n  })  \n\n\n  productForm.submit(function(event){\n      event.preventDefault();\n      // console.log(\"Form is not sending\")\n      var thisForm = $(this)\n      // var actionEndpoint = thisForm.attr(\"action\"); // API Endpoint\n      var actionEndpoint = thisForm.attr(\"data-endpoint\")\n      var httpMethod = thisForm.attr(\"method\");\n      var formData = thisForm.serialize();\n\n      $.ajax({\n        url: actionEndpoint,\n        method: httpMethod,\n        data: formData,\n        success: function(data){\n          var submitSpan = thisForm.find(\".submit-span\")\n          if (data.added){\n            submitSpan.html(\"<div class='btn-group'> <a class='btn btn-link' href='/cart/'>In cart</a> <button type='submit' class='btn btn-link'>Remove?</button></div>\")\n          } else {\n            submitSpan.html(\"<button type='submit'  class='btn btn-success'>Add to cart</button>\")\n           }\n          var navbarCount = $(\".navbar-cart-count\")\n          navbarCount.text(data.cartItemCount)\n          var currentPath = window.location.href\n\n          if (currentPath.indexOf(\"cart\") != -1) {\n            refreshCart()\n          }\n        },\n        error: function(errorData){\n          $.alert({\n            title: \"Oops!\",\n            content: \"An error occurred\",\n            theme: \"modern\",\n          })\n        }\n      })\n\n  })\n\n  function refreshCart(){\n    console.log(\"in current cart\")\n    var cartTable = $(\".cart-table\")\n    var cartBody = cartTable.find(\".cart-body\")\n    //cartBody.html(\"<h1>Changed</h1>\")\n    var productRows = cartBody.find(\".cart-product\")\n    var currentUrl = window.location.href\n\n    var refreshCartUrl = '/api/cart/'\n    var refreshCartMethod = \"GET\";\n    var data = {};\n    $.ajax({\n      url: refreshCartUrl,\n      method: refreshCartMethod,\n      data: data,\n      success: function(data){\n        \n        var hiddenCartItemRemoveForm = $(\".cart-item-remove-form\")\n        if (data.products.length > 0){\n            productRows.html(\" \")\n            i = data.products.length\n            $.each(data.products, function(index, value){\n              console.log(value)\n              var newCartItemRemove = hiddenCartItemRemoveForm.clone()\n              newCartItemRemove.css(\"display\", \"block\")\n              // newCartItemRemove.removeClass(\"hidden-class\")\n              newCartItemRemove.find(\".cart-item-product-id\").val(value.id)\n                cartBody.prepend(\"<tr><th scope=\\\"row\\\">\" + i + \"</th><td><a href='\" + value.url + \"'>\" + value.name + \"</a>\" + newCartItemRemove.html() + \"</td><td>\" + value.price + \"</td></tr>\")\n                i --\n            })\n            \n            cartBody.find(\".cart-subtotal\").text(data.subtotal)\n            cartBody.find(\".cart-total\").text(data.total)\n        } else {\n          window.location.href = currentUrl\n        }\n        \n      },\n      error: function(errorData){\n        $.alert({\n            title: \"Oops!\",\n            content: \"An error occurred\",\n            theme: \"modern\",\n          })\n      }\n    })\n\n\n  }\n\n\n\n})\n"
  },
  {
    "path": "src/static_my_proj/js/ecommerce.main.js",
    "content": "$(document).ready(function(){\n\n\nvar stripeFormModule = $(\".stripe-payment-form\")\nvar stripeModuleToken = stripeFormModule.attr(\"data-token\")\nvar stripeModuleNextUrl = stripeFormModule.attr(\"data-next-url\")\nvar stripeModuleBtnTitle = stripeFormModule.attr(\"data-btn-title\") || \"Add card\"\n\nvar stripeTemplate = $.templates(\"#stripeTemplate\")\nvar stripeTemplateDataContext = {\n    publishKey: stripeModuleToken,\n    nextUrl: stripeModuleNextUrl,\n    btnTitle: stripeModuleBtnTitle\n}\nvar stripeTemplateHtml  = stripeTemplate.render(stripeTemplateDataContext)\nstripeFormModule.html(stripeTemplateHtml)\n\n\n\n\n// https secure site when live\n\nvar paymentForm = $(\".payment-form\")\nif (paymentForm.length > 1){\n    alert(\"Only one payment form is allowed per page\")\n    paymentForm.css('display', 'none')\n}\nelse if (paymentForm.length == 1) {\n\nvar pubKey = paymentForm.attr('data-token')\nvar nextUrl = paymentForm.attr('data-next-url')\n    // Create a Stripe client\nvar stripe = Stripe(pubKey);\n\n// Create an instance of Elements\nvar elements = stripe.elements();\n\n// Custom styling can be passed to options when creating an Element.\n// (Note that this demo uses a wider set of styles than the guide below.)\nvar style = {\n  base: {\n    color: '#32325d',\n    lineHeight: '24px',\n    fontFamily: '\"Helvetica Neue\", Helvetica, sans-serif',\n    fontSmoothing: 'antialiased',\n    fontSize: '16px',\n    '::placeholder': {\n      color: '#aab7c4'\n    }\n  },\n  invalid: {\n    color: '#fa755a',\n    iconColor: '#fa755a'\n  }\n};\n\n// Create an instance of the card Element\nvar card = elements.create('card', {style: style});\n\n// Add an instance of the card Element into the `card-element` <div>\ncard.mount('#card-element');\n\n// Handle real-time validation errors from the card Element.\ncard.addEventListener('change', function(event) {\n  var displayError = document.getElementById('card-errors');\n  if (event.error) {\n    displayError.textContent = event.error.message;\n  } else {\n    displayError.textContent = '';\n  }\n});\n\n// Handle form submission\n// var form = document.getElementById('payment-form');\n// form.addEventListener('submit', function(event) {\n//   event.preventDefault();\n//   // get the btn\n//   // display new btn ui\n//   var loadTime = 1500\n//   var errorHtml = \"<i class='fa fa-warning'></i> An error occured\"\n//   var errorClasses = \"btn btn-danger disabled my-3\"\n//   var loadingHtml = \"<i class='fa fa-spin fa-spinner'></i> Loading...\"\n//   var loadingClasses = \"btn btn-success disabled my-3\"\n\n//   stripe.createToken(card).then(function(result) {\n//     if (result.error) {\n//       // Inform the user if there was an error\n//       var errorElement = document.getElementById('card-errors');\n//       errorElement.textContent = result.error.message;\n//     } else {\n//       // Send the token to your server\n//       stripeTokenHandler(nextUrl, result.token);\n//     }\n//   });\n// });\n\nvar form = $('#payment-form');\nvar btnLoad = form.find(\".btn-load\")\nvar btnLoadDefaultHtml = btnLoad.html()\nvar btnLoadDefaultClasses = btnLoad.attr(\"class\")\n\nform.on('submit', function(event) {\n  event.preventDefault();\n  // get the btn\n  // display new btn ui\n  var $this = $(this)\n  // btnLoad = $this.find('.btn-load')\n  btnLoad.blur()\n  var loadTime = 1500\n  var currentTimeout;\n  var errorHtml = \"<i class='fa fa-warning'></i> An error occured\"\n  var errorClasses = \"btn btn-danger disabled my-3\"\n  var loadingHtml = \"<i class='fa fa-spin fa-spinner'></i> Loading...\"\n  var loadingClasses = \"btn btn-success disabled my-3\"\n\n  stripe.createToken(card).then(function(result) {\n    if (result.error) {\n      // Inform the user if there was an error\n      var errorElement = $('#card-errors');\n      errorElement.textContent = result.error.message;\n      currentTimeout = displayBtnStatus(\n                            btnLoad, \n                            errorHtml, \n                            errorClasses, \n                            1000, \n                            currentTimeout\n                        )\n\n\n    } else {\n      // Send the token to your server\n      currentTimeout = displayBtnStatus(\n                            btnLoad, \n                            loadingHtml, \n                            loadingClasses, \n                            10000, \n                            currentTimeout\n                        )\n\n      stripeTokenHandler(nextUrl, result.token);\n\n    }\n  });\n});\n\n\nfunction displayBtnStatus(element, newHtml, newClasses, loadTime, timeout){\n    // if (timeout){\n    //   clearTimeout(timeout)\n    // }\n    if (!loadTime){\n      loadTime = 1500\n    }\n    //var defaultHtml = element.html()\n    //var defaultClasses = element.attr(\"class\")\n    element.html(newHtml)\n    element.removeClass(btnLoadDefaultClasses)\n    element.addClass(newClasses)\n    return setTimeout(function(){\n        element.html(btnLoadDefaultHtml)\n        element.removeClass(newClasses)\n        element.addClass(btnLoadDefaultClasses)\n    }, loadTime)\n}\n\n\nfunction redirectToNext(nextPath, timeoffset) {\n    // body...\n    if (nextPath){\n    setTimeout(function(){\n                window.location.href = nextPath\n            }, timeoffset)\n    }\n}\n\nfunction stripeTokenHandler(nextUrl, token){\n    // console.log(token.id)\n    var paymentMethodEndpoint = '/billing/payment-method/create/'\n    var data = {\n        'token': token.id\n    }\n    $.ajax({\n        data: data,\n        url: paymentMethodEndpoint,\n        method: \"POST\",\n        success: function(data){\n            var succesMsg = data.message || \"Success! Your card was added.\"\n            card.clear()\n            if (nextUrl){\n                succesMsg = succesMsg + \"<br/><br/><i class='fa fa-spin fa-spinner'></i> Redirecting...\"\n            }\n            if ($.alert){\n                $.alert(succesMsg)\n            } else {\n                alert(succesMsg)\n            }\n            btnLoad.html(btnLoadDefaultHtml)\n            btnLoad.attr('class', btnLoadDefaultClasses)\n            redirectToNext(nextUrl, 1500)\n            \n        },\n        error: function(error){\n            // console.log(error)\n            $.alert({title: \"An error occured\", content:\"Please try adding your card again.\"})\n            btnLoad.html(btnLoadDefaultHtml)\n            btnLoad.attr('class', btnLoadDefaultClasses)\n        }\n    })\n}\n}\n\n})"
  },
  {
    "path": "src/static_my_proj/js/ecommerce.sales.js",
    "content": "\n$(document).ready(function(){\n    function renderChart(id, data, labels){\n        // var ctx = document.getElementById(\"myChart\").getContext('2d');\n        var ctx = $('#' + id)\n            var myChart = new Chart(ctx, {\n                type: 'line',\n                data: {\n                    labels: labels,\n                    datasets: [{\n                        label: 'Sales',\n                        data: data,\n                       backgroundColor: 'rgba(0, 158, 29, 0.45)',\n                        borderColor:'rgba(0, 158, 29, 1)',\n                    }]\n                },\n                options: {\n                    scales: {\n                        yAxes: [{\n                            ticks: {\n                                beginAtZero:true\n                            }\n                        }]\n                    },\n                    backgroundColor: 'rgba(75, 192, 192, 1)'\n                }\n            });\n    }\n\n    function getSalesData(id, type){\n        var url = '/analytics/sales/data/'\n        var method = 'GET'\n        var data = {\"type\": type}\n        $.ajax({\n            url: url,\n            method: method,\n            data: data,\n            success: function(responseData){\n                renderChart(id, responseData.data, responseData.labels)\n            }, error: function(error){\n                $.alert(\"An error occurred\")\n            }\n        })\n    }\n    var chartsToRender = $('.cfe-render-chart')\n    $.each(chartsToRender, function(index, html){\n        var $this = $(this)\n        if ( $this.attr('id') && $this.attr('data-type')){\n            getSalesData($this.attr('id'), $this.attr('data-type'))\n        }\n        \n    })\n    \n})"
  },
  {
    "path": "src/tags/__init__.py",
    "content": ""
  },
  {
    "path": "src/tags/admin.py",
    "content": "from django.contrib import admin\n\nfrom .models import Tag\n\nadmin.site.register(Tag)"
  },
  {
    "path": "src/tags/apps.py",
    "content": "from django.apps import AppConfig\n\n\nclass TagsConfig(AppConfig):\n    name = 'tags'\n"
  },
  {
    "path": "src/tags/migrations/0001_initial.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-21 00:00\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    initial = True\n\n    dependencies = [\n        ('products', '0009_product_timestamp'),\n    ]\n\n    operations = [\n        migrations.CreateModel(\n            name='Tag',\n            fields=[\n                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),\n                ('title', models.CharField(max_length=120)),\n                ('slug', models.SlugField()),\n                ('timestamp', models.DateTimeField(auto_now_add=True)),\n                ('active', models.BooleanField(default=True)),\n                ('products', models.ManyToManyField(blank=True, to='products.Product')),\n            ],\n        ),\n    ]\n"
  },
  {
    "path": "src/tags/migrations/__init__.py",
    "content": ""
  },
  {
    "path": "src/tags/models.py",
    "content": "from django.db import models\nfrom django.db.models.signals import pre_save, post_save\nfrom django.urls import reverse\n\nfrom ecommerce.utils import unique_slug_generator\nfrom products.models import Product\n\n\nclass Tag(models.Model):\n    title       = models.CharField(max_length=120)\n    slug        = models.SlugField()\n    timestamp   = models.DateTimeField(auto_now_add=True)\n    active      = models.BooleanField(default=True)\n    products    = models.ManyToManyField(Product, blank=True)\n\n    def __str__(self):\n        return self.title\n\n\ndef tag_pre_save_receiver(sender, instance, *args, **kwargs):\n    if not instance.slug:\n        instance.slug = unique_slug_generator(instance)\n\npre_save.connect(tag_pre_save_receiver, sender=Tag)"
  },
  {
    "path": "src/tags/shell_commands.py",
    "content": "'''\n# Shell session 1\n# python manage.py shell\n'''\n\nfrom tags.models import Tag\n\nqs = Tag.objects.all()\nprint(qs)\nblack = Tag.objects.last()\nblack.title\nblack.slug\n\nblack.products\n\"\"\"\nReutrns: \n<django.db.models.fields.related_descriptors.create_forward_many_to_many_manager.<locals>.ManyRelatedManager object at 0x1112f3fd0>\n\"\"\"\n\nblack.products.all()\n\"\"\"\nThis is an actual queryset of PRODUCTS\nMuch like Products.objects.all(), but in this case it's ALL of the products that are \nrelated to the \"Black\" tag\n\"\"\"\nblack.products.all().first()\n\"\"\"\nreturns the first instance, if any\n\"\"\"\n\nexit()\n\n'''\n# Shell session 2\n# python manage.ppy shell\n'''\nfrom products.models import Product\n\n\n\nqs = Product.objects.all()\nprint(qs)\ntshirt = qs.first()\ntshirt.title\ntshirt.description\n\ntshirt.tag\n'''\nRaises an error because the Product model doens't have a field \"tag\"\n'''\n\ntshirt.tags\n'''\nRaises an error because the Product model doens't have a field \"tags\"\n'''\n\ntshirt.tag_set\n'''\nThis works because the Tag model has the \"products\" field with the ManyToMany to Product\n<django.db.models.fields.related_descriptors.create_forward_many_to_many_manager.<locals>.ManyRelatedManager object at 0x10c0e75f8>\n'''\n\ntshirt.tag_set.all()\n'''\nReturns an actual Queryset of the Tag model related to this product\n<QuerySet [<Tag: T shirt>, <Tag: TShirt>, <Tag: T-shirt>, <Tag: Red>, <Tag: Black>]>\n'''\ntshirt.tag_set.filter(title__icontains='black')\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "src/tags/tests.py",
    "content": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "src/tags/views.py",
    "content": "from django.shortcuts import render\n\n# Create your views here.\n"
  },
  {
    "path": "src/templates/400.html",
    "content": "{% extends \"base.html\" %}\n\n\n{% block content %}\n<div class='row'>\n<div class='col text-center'>\n\n    <h1 class='my-5'>Bad Request</h1>\n    <p>400 Error</p>\n\n</div>\n</div>\n{% endblock %}"
  },
  {
    "path": "src/templates/403.html",
    "content": "{% extends \"base.html\" %}\n\n\n{% block content %}\n<div class='row'>\n<div class='col text-center'>\n\n    \n    <h1 class='my-5'>Permission Denied</h1>\n    <p>403 Error</p>\n\n</div>\n</div>\n{% endblock %}"
  },
  {
    "path": "src/templates/404.html",
    "content": "{% extends \"base.html\" %}\n\n\n{% block content %}\n<div class='row'>\n<div class='col text-center'>\n\n    <h1 class='my-5'>Page Not Found</h1>\n    <p>404 Error</p>\n\n</div>\n</div>\n{% endblock %}"
  },
  {
    "path": "src/templates/500.html",
    "content": "{% extends \"base.html\" %}\n\n\n{% block content %}\n<div class='row'>\n<div class='col text-center'>\n\n    <h1 class='my-5'>Oops. Sorry. A Server Error Occured</h1>\n    <p>500 Error | We have been notified and are working on a fix. </p>\n\n</div>\n</div>\n{% endblock %}"
  },
  {
    "path": "src/templates/base/css.html",
    "content": "{% load static %}\n<!-- Bootstrap CSS -->\n<link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n\n<!-- Fontawesome CSS -->\n<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css' />\n\n<!-- jquery-confirm CSS -->\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/jquery-confirm/3.3.0/jquery-confirm.min.css\">\n\n\n<!-- Custom Stripe Styling -->\n<link rel=\"stylesheet\" href=\"{% static 'css/stripe-custom-style.css' %}\">"
  },
  {
    "path": "src/templates/base/forms.html",
    "content": "{% extends \"base.html\" %}\n\n\n{% block content %}\n<div class='col-12 col-md-6 mx-auto'>\n{% if title %}<h1 class='my-3'>{{ title }}</h1>{% endif %}\n<form method='POST' action='{% if action_url %}{{ action_url }}{% endif %}'> {% csrf_token %}\n    {% if next_url %}\n    <input type='hidden' name='next' value='{{ next_url }}' />\n    {% endif %}\n  {{ form.as_p }}\n  <button type='submit' class='btn btn-default'>Save</button>\n</form>\n</div>\n{% endblock %}"
  },
  {
    "path": "src/templates/base/js.html",
    "content": "{% load static %}\n<!-- Optional JavaScript -->\n<!-- jQuery first, then Popper.js, then Bootstrap JS\nslim is missing ajax -->\n<script src=\"https://code.jquery.com/jquery-3.2.1.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js\" integrity=\"sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4\" crossorigin=\"anonymous\"></script>\n<script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js\" integrity=\"sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1\" crossorigin=\"anonymous\"></script>\n\n<!-- Stripe JS -->\n<script src=\"https://js.stripe.com/v3/\"></script>\n\n\n<!-- jquery-confirm JS -->\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery-confirm/3.3.0/jquery-confirm.min.js\"></script>\n\n<!-- js Render -->\n<script src='https://cdnjs.cloudflare.com/ajax/libs/jsrender/0.9.88/jsrender.min.js'></script>\n{% include 'base/js_templates.html' %}\n\n\n<!-- Chart.js -->\n<script src='https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.min.js'></script>\n\n<!-- Django Secure AJAX JS -->\n<script src='{% static \"js/csrf.ajax.js\" %}'></script>\n\n<!-- eCommerce Sales Data JS -->\n<script src='{% static \"js/ecommerce.sales.js\" %}'></script>\n\n<!-- eCommerce Custom JS -->\n<script src='{% static \"js/ecommerce.js\" %}'></script>\n\n<!-- eCommerce Main JS -->\n<script src='{% static \"js/ecommerce.main.js\" %}'></script>\n\n\n\n\n\n"
  },
  {
    "path": "src/templates/base/js_templates.html",
    "content": "{% verbatim %}\n<!-- stripe template form -->\n<script id=\"stripeTemplate\" type=\"text/x-jsrender\">\n    <form class='payment-form' action=\"\" method=\"post\" id=\"payment-form\" data-token='{{:publishKey}}' data-next-url='{{:nextUrl}}'>\n  <div class=\"form-row\">\n    <!-- <label for=\"card-element\">\n      Credit or debit card\n    </label> -->\n    <div id=\"card-element\" class='form-control'> \n      <!-- a Stripe Element will be inserted here. -->\n    </div>\n\n    <!-- Used to display form errors -->\n    <div id=\"card-errors\" role=\"alert\"></div>\n  </div>\n\n  <button class='btn btn-primary my-3 btn-load'>{{:btnTitle }}</button>\n\n    </form>\n\n</script>\n{% endverbatim %}"
  },
  {
    "path": "src/templates/base/navbar.html",
    "content": "{% url 'home' as home_url %}\n{% url 'contact' as contact_url %}\n{% url 'products:list' as product_list_url %}\n{% url 'login' as login_url %}\n{% url 'logout' as logout_url %}\n{% url 'register' as register_url %}\n\n{% url 'account:home' as account_url %}\n{% url 'cart:home' as cart_url %}\n\n<nav class=\"navbar navbar-expand-lg navbar-dark bg-dark mb-3\">\n   <div class='container'>\n  <a class=\"navbar-brand\" href=\"{{ home_url }}\">\n    <img src=\"//getbootstrap.com/assets/brand/bootstrap-solid.svg\" width=\"30\" height=\"30\" class=\"d-inline-block align-top\" alt=\"\">\n    {% if brand_name %} {{brand_name }} {% else %}CFE eCommerce {% endif %}\n  </a>\n  <button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\"#navbarSupportedContent\" aria-controls=\"navbarSupportedContent\" aria-expanded=\"false\" aria-label=\"Toggle navigation\">\n    <span class=\"navbar-toggler-icon\"></span>\n  </button>\n\n  <div class=\"collapse navbar-collapse\" id=\"navbarSupportedContent\">\n    <ul class=\"navbar-nav mr-auto\">\n      <li class=\"nav-item {% if request.path == home_url %}active{% endif %}\">\n        <a class=\"nav-link\" href=\"{{ home_url }}\">Home <span class=\"sr-only\">(current)</span></a>\n      </li>\n      <li class=\"nav-item {% if request.path == contact_url %}active{% endif %}\">\n        <a class=\"nav-link\" href=\"{{ contact_url }}\">Contact</a>\n      </li>\n      <li class=\"nav-item {% if request.path == product_list_url %}active{% endif %}\">\n        <a class=\"nav-link\" href=\"{{ product_list_url }}\">Products</a>\n      </li>\n\n\n      {% if request.user.is_authenticated %}\n       <li class=\"nav-item dropdown\">\n        <a class=\"nav-link dropdown-toggle\" href=\"#\" id=\"navbarDropdown\" role=\"button\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">\n          Account\n        </a>\n        <div class=\"dropdown-menu\" aria-labelledby=\"navbarDropdown\">\n          <a class=\"dropdown-item {% if request.path == account_url %}active{% endif %}\" href=\"{{ account_url }}\">Home</a>\n          <a class=\"dropdown-item\" href=\"{{ account_url }}#billing\">Billing</a>\n          <a class=\"dropdown-item\" href=\"{% url \"account:user-product-history\" %}\">History</a>\n          <a class='dropdown-item' href='{% url \"library\" %}'>Library</a>\n          <div class=\"dropdown-divider\"></div>\n          <a class=\"dropdown-item\" href=\"{{ logout_url }}\">Logout</a>\n        </div>\n      </li>\n      {% else %}\n       <li class=\"nav-item {% if request.path == register_url %}active{% endif %}\">\n        <a class=\"nav-link\" href=\"{{ register_url }}\">Register</a>\n      </li>\n      <li class=\"nav-item {% if request.path == login_url %}active{% endif %}\">\n        <a class=\"nav-link\" href=\"{{ login_url }}\">Login</a>\n      </li>\n      {% endif %}\n      <li class=\"nav-item {% if request.path == cart_url %}active{% endif %}\">\n        <a class=\"nav-link\" href=\"{{ cart_url }}\"><span class='navbar-cart-count'>{{ request.session.cart_items }}</span> <i class=\"fa fa-shopping-cart\" aria-hidden=\"true\"></i></a>\n      </li>\n\n       <!--  <li class=\"nav-item dropdown\">\n            <a class=\"nav-link dropdown-toggle\" href=\"http://example.com\" id=\"navbarDropdownMenuLink\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">\n              Dropdown link\n            </a>\n            <div class=\"dropdown-menu dropdown-menu-left\" aria-labelledby=\"navbarDropdownMenuLink\">\n              <a class=\"dropdown-item\" href=\"#\">Action</a>\n              <a class=\"dropdown-item\" href=\"#\">Another action</a>\n              <a class=\"dropdown-item\" href=\"#\">Something else here</a>\n            </div>\n          </li> -->\n\n    </ul>\n    {% include 'search/snippets/search-form.html' %}\n  </div>\n</div>\n</nav>"
  },
  {
    "path": "src/templates/base.html",
    "content": "{% load static %}\n<!DOCTYPE html>\n    <html lang=\"en\">\n    <head>\n      <!-- Required meta tags -->\n      <meta charset=\"utf-8\">\n      <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n      <title>Base Template</title>\n        {% include 'base/css.html' %}\n        {% block base_head %}{% endblock %}\n    </head>\n    <body>\n      {% include 'base/navbar.html' with brand_name='eCommerce' %}\n      <div class='container'>\n        {% if messages %}\n      <div class=\"alert alert-success messages\">\n          {% for message in messages %}\n          <span{% if message.tags %} class=\"{{ message.tags }}\"{% endif %}>\n              {% if message.level == DEFAULT_MESSAGE_LEVELS.ERROR %}Important: {% endif %}\n              {{ message }}<br/>\n          </span>\n          {% endfor %}\n      </div>\n      {% endif %}\n      {% block content %}{% endblock %}\n    </div>\n\n        {% include 'base/js.html' %}\n        {% block javascript %}\n\n        {% endblock %}\n    </body>\n  </html>"
  },
  {
    "path": "src/templates/bootstrap/example.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <!-- Required meta tags -->\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n\n    <!-- Bootstrap CSS -->\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n  </head>\n  <body>\n\n\n<nav class=\"navbar navbar-expand-md navbar-dark bg-dark\">\n   <div class='container'>\n      <a class=\"navbar-brand\" href=\"#\">\n        <img src=\"http://getbootstrap.com/assets/brand/bootstrap-solid.svg\" width=\"30\" height=\"30\" class=\"d-inline-block align-top\" alt=\"\">\n        Bootstrap\n      </a>\n      <button class='navbar-toggler' type='button' data-toggle='collapse' data-target='#navbarCollapseLinks' aria-expanded='false' aria-label='Toggle Navigation'>\n        <span class='navbar-toggler-icon'></span>\n      </button>\n\n\n\n\n      <div class='collapse navbar-collapse' id='navbarCollapseLinks'>\n        <ul class='navbar-nav'>\n          <li class='nav-item'>\n            <a href='#' class='nav-link'>Home</a>\n          </li>\n          <li class='nav-item'>\n            <a href='#' class='nav-link'>About</a>\n          </li>\n          <li class='nav-item'>\n            <a href='#' class='nav-link'>Products</a>\n          </li>\n          <li class=\"nav-item dropdown\">\n            <a class=\"nav-link dropdown-toggle\" href=\"http://example.com\" id=\"navbarDropdownMenuLink\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">\n              Dropdown link\n            </a>\n            <div class=\"dropdown-menu dropdown-menu-left\" aria-labelledby=\"navbarDropdownMenuLink\">\n              <a class=\"dropdown-item\" href=\"#\">Action</a>\n              <a class=\"dropdown-item\" href=\"#\">Another action</a>\n              <a class=\"dropdown-item\" href=\"#\">Something else here</a>\n            </div>\n          </li>\n\n        </ul>\n\n\n        <form class=\"form-inline ml-auto\">\n          <input class=\"form-control mr-sm-2\" type=\"text\" placeholder=\"Search\" aria-label=\"Search\">\n          <button class=\"btn btn-outline-success my-2 my-sm-0\" type=\"submit\">Search</button>\n        </form>\n      </div>\n  </div>\n</nav>\n\n\n\n\n\n\n    <div class='container'>\n        <div class='row'>\n            <div class='col-12'>\n                <div class=\"alert alert-secondary\" role=\"alert\">\n                Nav\n                </div>\n            </div>\n\n        </div>\n\n        <div class='row mb-3'>\n\n          <div class='col-12 col-sm-12 col-md-6 col-lg-4 ml-auto'>\n            <input type='text' class='form-control' placeholder=\"Search\">\n          </div>\n\n        </div>\n        <div class='row'>\n            <div class='col-11 mx-auto col-lg-2 order-12'>\n                <div class=\"alert alert-primary\" role=\"alert\">\n                Bottom Content Item\n                </div>\n            </div>\n            <div class='col-11 col-lg-8 mx-auto order-6' >\n                <div class=\"alert alert-primary\" role=\"alert\" style='min-height: 800px;'>\n                Middle\n\n                <div class='row'>\n                  <div class='col-8'>\n                      <div class=\"alert alert-primary\" role=\"alert\">\n                      This is a primary alert—check it out!\n                      </div>\n                  </div>\n                  <div class='col-4'>\n                      <div class=\"alert alert-secondary\" role=\"alert\">\n                      This is a primary alert—check it out!\n                      </div>\n                  </div>\n\n                </div>\n                <div class='row'>\n                <div class='col-1'>\n                    <div class=\"alert alert-primary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-secondary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-primary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-secondary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-primary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-secondary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-primary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-secondary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-primary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-secondary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-primary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-secondary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                 \n            </div>\n\n\n\n                </div>\n            </div>\n            <div class='col-12 col-lg-2 order-1'>\n                <div class=\"alert alert-secondary\" role=\"alert\">\n                Top Content Item\n                </div>\n            </div>\n\n        </div>\n\n\n    </div>\n\n\n\n\n\n\n\n\n    <div class='container'>\n            <div class='row'>\n                <div class='col-1'>\n                    <div class=\"alert alert-primary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-secondary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-primary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-secondary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-primary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-secondary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-primary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-secondary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-primary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-secondary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-primary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-secondary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                 \n            </div>\n\n    </div>\n    <div class='container-fluid'>\n        <div class='row'>\n                <div class='col-1'>\n                    <div class=\"alert alert-primary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-secondary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-primary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-secondary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-primary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-secondary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-primary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-secondary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-primary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-secondary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-primary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                <div class='col-1'>\n                    <div class=\"alert alert-secondary\" role=\"alert\">\n                    This is a primary alert—check it out!\n                    </div>\n                </div>\n                \n            </div>\n    </div>\n\n    <!-- Optional JavaScript -->\n    <!-- jQuery first, then Popper.js, then Bootstrap JS -->\n    <script src=\"https://code.jquery.com/jquery-3.2.1.slim.min.js\" integrity=\"sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN\" crossorigin=\"anonymous\"></script>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js\" integrity=\"sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4\" crossorigin=\"anonymous\"></script>\n    <script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js\" integrity=\"sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1\" crossorigin=\"anonymous\"></script>\n  </body>\n</html>"
  },
  {
    "path": "src/templates/contact/view.html",
    "content": "{% extends \"base.html\" %}\n\n\n{% block content %}\n<div class='text-center'>\n          <h1>{{ title }}</h1>\n          <h1>Hello, world we're working!</h1>\n      </div>\n      <div class='container'>\n      <div class='row'>\n        <div class='col'>\n            \n            <div class='col-md-6 col-12 mx-auto'>\n              <p>{{ content }}</p>\n            <form class='contact-form' method='POST' action='{% url \"contact\" %}'> {% csrf_token %}\n              {{ form.as_p }}\n              <button type='submit' class='btn btn-default'>Submit</button>\n            </form>\n\n\n            <!-- <form method='POST'> {% csrf_token %}\n              <input type='text' class='form-control' placeholder=\"Name\" name='fullname'>\n              <input type='email' class='form-control' placeholder=\"Email\" name='email'>\n              <textarea name='content' class='form-control' placeholder=\"Your content\"></textarea>\n              <button type='submit' class='btn btn-default'>Submit</button>\n            </form> -->\n            </div>\n        </div>\n      </div>\n      </div>\n{% endblock %}"
  },
  {
    "path": "src/templates/home_page.html",
    "content": "{% extends \"base.html\" %}\n{% load static %}\n\n<title>Home Page Template</title>\n\n{% block base_head %}\n<link rel='stylesheet' href='{% static \"css/main.css\" %}' >\n{% endblock %}\n\n{% block content %}\n<div class='text-center'>\n    <h1>{{ title }}</h1>\n    <h1>Hello, world we're working!</h1>\n</div>\n\n<div class='row'>\n  <div class='col'>\n      <img src=\"{% static 'img/beach.jpg' %}\" class='img-fluid' />\n      <p>{{ content }}</p>\n  </div>\n</div>\n{% if request.user.is_authenticated %}\n<div class='row'>\n  <div class='col'>\n  <h1>Premium</h1>\n  {{ premium_content }}\n  </div>\n</div>\n{% endif %}\n\n\n{% endblock %}\n\n<!DOCTYPE html>\n    <html lang=\"en\">\n    <head>\n      <!-- Required meta tags -->\n      <meta charset=\"utf-8\">\n      <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n\n      <!-- Bootstrap CSS -->\n      <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n      <link rel='stylesheet' href='{% static \"css/main.css\" %}' >\n    </head>\n    <body>\n      <div class='text-center'>\n          <h1>{{ title }}</h1>\n          <h1>Hello, world we're working!</h1>\n      </div>\n      <div class='container'>\n        <div class='row'>\n          <div class='col'>\n              <img src=\"{% static 'img/beach.jpg' %}\" class='img-fluid' />\n              <p>{{ content }}</p>\n          </div>\n        </div>\n        {% if request.user.is_authenticated %}\n        <div class='row'>\n          <div class='col'>\n          <h1>Premium</h1>\n          {{ premium_content }}\n          </div>\n        </div>\n        {% endif %}\n      </div>\n      <!-- Optional JavaScript -->\n      <!-- jQuery first, then Popper.js, then Bootstrap JS -->\n      <script src=\"https://code.jquery.com/jquery-3.2.1.slim.min.js\" integrity=\"sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN\" crossorigin=\"anonymous\"></script>\n      <script src=\"https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js\" integrity=\"sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4\" crossorigin=\"anonymous\"></script>\n      <script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js\" integrity=\"sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1\" crossorigin=\"anonymous\"></script>\n    </body>\n  </html>"
  },
  {
    "path": "src/templates/registration/activation-error.html",
    "content": "{% extends \"base.html\" %}\n{% block content %}\n<div class='row'>\n    <div class=\"col-12 text-center py-5\">\n            {% if key %}\n                <h1 class='my-5 py-5'>Activation Error. Please try again.</h1>\n            {% else %}\n                <h1 class='my-5 py-5'>Re-activate your Email Below.</h1>\n            {% endif %}\n      </div>\n        <div class=\"col-12 text-center\">\n            <form method='POST' action=''>{% csrf_token %}\n                {{ form.as_p }}\n                <input class='btn btn-default' type='submit' value='Resend Activation' />\n            </form>\n      </div>\n</div>\n{% endblock %}\n"
  },
  {
    "path": "src/templates/registration/emails/verify.html",
    "content": "<p>Hello,</p>\n\n<p>Please activate your account for {{ email }} by clicking the link below:</p>\n\n<p><a href='{{ path }}'>{{ path }}</a></p>\n<p>Once you activate, you can login!</p>\n<p>Thank you,</p>\n<p>Python eCommerce</p>\n"
  },
  {
    "path": "src/templates/registration/emails/verify.txt",
    "content": "Hello,\n\nPlease activate your account for {{ email }} by clicking the link below:\n\n\n\n{{ path }}\n\n\n\nOnce you activate, you can login!\n\nThank you,\n\nPython eCommerce"
  },
  {
    "path": "src/templates/registration/password_change_done.html",
    "content": "{% extends \"base.html\" %}\n{% block content %}\n<div class='row'>\n    <div class=\"col-12 text-center py-5\">\n            <h1 class='my-5 py-5'>Password successfully changed!</h1>\n      </div>\n</div>\n{% endblock %}\n"
  },
  {
    "path": "src/templates/registration/password_change_form.html",
    "content": "{% extends \"base.html\" %}\n{% block content %}\n<div class='row'>\n    <div class='col-md-6 col-10  mx-auto'>\n    <h1>Change your Password</h1>\n        <form method='post' action=''>{% csrf_token %}\n           {{ form.as_p }}\n        <span style='margin-bottom: 12px;'></span>\n        <button type=\"submit\" class='btn btn-block btn-info'>Save</button>\n        </form>\n      </div>\n</div>\n{% endblock %}\n"
  },
  {
    "path": "src/templates/registration/password_reset_complete.html",
    "content": "{% extends \"base.html\" %}\n{% block content %}\n<div class='row'>\n    <div class=\"col-12 text-center py-5\">\n            <h1 class='my-5 py-5'>Password reset complete</h1>\n            <a href='/login'>Login</a>\n      </div>\n</div>\n{% endblock %}\n"
  },
  {
    "path": "src/templates/registration/password_reset_confirm.html",
    "content": "{% extends \"base.html\" %}\n{% block content %}\n<div class='row'>\n    <div class='col-md-4 col-10  mx-auto'>\n        <h1>Set your Password</h1>\n        <form method='post' action=''>{% csrf_token %}\n        {{ form.as_p }}\n        <span style='margin-bottom: 12px;'></span>\n        <button type=\"submit\" class='btn btn-block btn-info'>Set new password</button>\n        </form>\n      </div>\n</div>\n{% endblock %}\n"
  },
  {
    "path": "src/templates/registration/password_reset_done.html",
    "content": "{% extends \"base.html\" %}\n{% block content %}\n<div class='row'>\n    <div class=\"col-12 text-center py-5\">\n            <h1 class='my-5 py-5'>Rest Instructions Sent</h1>\n            <p>Please check your email</p>\n      </div>\n</div>\n{% endblock %}\n"
  },
  {
    "path": "src/templates/registration/password_reset_email.html",
    "content": "{% load i18n %}\n{% blocktrans %}\nHello, \n\nReset your password on {{ domain }} for {{ user }}:\n{% endblocktrans %}\n\n{% block reset_link %}\n{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}\n\n{% endblock %}\n"
  },
  {
    "path": "src/templates/registration/password_reset_email.txt",
    "content": "{% load i18n %}\n{% blocktrans %}\nHello, \n\nReset your password on {{ domain }} for {{ user }}:\n{% endblocktrans %}\n\n{% block reset_link %}\n{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}\n\n{% endblock %}\n"
  },
  {
    "path": "src/templates/registration/password_reset_form.html",
    "content": "{% extends \"base.html\" %}\n{% block content %}\n<div class='row'>\n    <div class='col-md-4 col-10  mx-auto'>\n    <h1>Reset your Password</h1>\n        <form method='post' action=''>{% csrf_token %}\n        {{ form.as_p }}\n        <span style='margin-bottom: 12px;'></span>\n        <button type=\"submit\" class='btn btn-block btn-info'>Reset Password</button>\n        </form>\n      </div>\n</div>\n{% endblock %}\n"
  },
  {
    "path": "static_cdn/media_root/products/2473283945/2473283945.sublime-project",
    "content": "{\n\t\"folders\":\n\t[\n\t\t{\n\t\t\t\"path\": \".\"\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "static_cdn/static_root/admin/css/base.css",
    "content": "/*\n    DJANGO Admin styles\n*/\n\n@import url(fonts.css);\n\nbody {\n    margin: 0;\n    padding: 0;\n    font-size: 14px;\n    font-family: \"Roboto\",\"Lucida Grande\",\"DejaVu Sans\",\"Bitstream Vera Sans\",Verdana,Arial,sans-serif;\n    color: #333;\n    background: #fff;\n}\n\n/* LINKS */\n\na:link, a:visited {\n    color: #447e9b;\n    text-decoration: none;\n}\n\na:focus, a:hover {\n    color: #036;\n}\n\na:focus {\n    text-decoration: underline;\n}\n\na img {\n    border: none;\n}\n\na.section:link, a.section:visited {\n    color: #fff;\n    text-decoration: none;\n}\n\na.section:focus, a.section:hover {\n    text-decoration: underline;\n}\n\n/* GLOBAL DEFAULTS */\n\np, ol, ul, dl {\n    margin: .2em 0 .8em 0;\n}\n\np {\n    padding: 0;\n    line-height: 140%;\n}\n\nh1,h2,h3,h4,h5 {\n    font-weight: bold;\n}\n\nh1 {\n    margin: 0 0 20px;\n    font-weight: 300;\n    font-size: 20px;\n    color: #666;\n}\n\nh2 {\n    font-size: 16px;\n    margin: 1em 0 .5em 0;\n}\n\nh2.subhead {\n    font-weight: normal;\n    margin-top: 0;\n}\n\nh3 {\n    font-size: 14px;\n    margin: .8em 0 .3em 0;\n    color: #666;\n    font-weight: bold;\n}\n\nh4 {\n    font-size: 12px;\n    margin: 1em 0 .8em 0;\n    padding-bottom: 3px;\n}\n\nh5 {\n    font-size: 10px;\n    margin: 1.5em 0 .5em 0;\n    color: #666;\n    text-transform: uppercase;\n    letter-spacing: 1px;\n}\n\nul li {\n    list-style-type: square;\n    padding: 1px 0;\n}\n\nli ul {\n    margin-bottom: 0;\n}\n\nli, dt, dd {\n    font-size: 13px;\n    line-height: 20px;\n}\n\ndt {\n    font-weight: bold;\n    margin-top: 4px;\n}\n\ndd {\n    margin-left: 0;\n}\n\nform {\n    margin: 0;\n    padding: 0;\n}\n\nfieldset {\n    margin: 0;\n    padding: 0;\n    border: none;\n    border-top: 1px solid #eee;\n}\n\nblockquote {\n    font-size: 11px;\n    color: #777;\n    margin-left: 2px;\n    padding-left: 10px;\n    border-left: 5px solid #ddd;\n}\n\ncode, pre {\n    font-family: \"Bitstream Vera Sans Mono\", Monaco, \"Courier New\", Courier, monospace;\n    color: #666;\n    font-size: 12px;\n}\n\npre.literal-block {\n    margin: 10px;\n    background: #eee;\n    padding: 6px 8px;\n}\n\ncode strong {\n    color: #930;\n}\n\nhr {\n    clear: both;\n    color: #eee;\n    background-color: #eee;\n    height: 1px;\n    border: none;\n    margin: 0;\n    padding: 0;\n    font-size: 1px;\n    line-height: 1px;\n}\n\n/* TEXT STYLES & MODIFIERS */\n\n.small {\n    font-size: 11px;\n}\n\n.tiny {\n    font-size: 10px;\n}\n\np.tiny {\n    margin-top: -2px;\n}\n\n.mini {\n    font-size: 10px;\n}\n\np.mini {\n    margin-top: -3px;\n}\n\n.help, p.help, form p.help, div.help, form div.help, div.help li {\n    font-size: 11px;\n    color: #999;\n}\n\ndiv.help ul {\n     margin-bottom: 0;\n}\n\n.help-tooltip {\n    cursor: help;\n}\n\np img, h1 img, h2 img, h3 img, h4 img, td img {\n    vertical-align: middle;\n}\n\n.quiet, a.quiet:link, a.quiet:visited {\n    color: #999;\n    font-weight: normal;\n}\n\n.float-right {\n    float: right;\n}\n\n.float-left {\n    float: left;\n}\n\n.clear {\n    clear: both;\n}\n\n.align-left {\n    text-align: left;\n}\n\n.align-right {\n    text-align: right;\n}\n\n.example {\n    margin: 10px 0;\n    padding: 5px 10px;\n    background: #efefef;\n}\n\n.nowrap {\n    white-space: nowrap;\n}\n\n/* TABLES */\n\ntable {\n    border-collapse: collapse;\n    border-color: #ccc;\n}\n\ntd, th {\n    font-size: 13px;\n    line-height: 16px;\n    border-bottom: 1px solid #eee;\n    vertical-align: top;\n    padding: 8px;\n    font-family: \"Roboto\", \"Lucida Grande\", Verdana, Arial, sans-serif;\n}\n\nth {\n    font-weight: 600;\n    text-align: left;\n}\n\nthead th,\ntfoot td {\n    color: #666;\n    padding: 5px 10px;\n    font-size: 11px;\n    background: #fff;\n    border: none;\n    border-top: 1px solid #eee;\n    border-bottom: 1px solid #eee;\n}\n\ntfoot td {\n    border-bottom: none;\n    border-top: 1px solid #eee;\n}\n\nthead th.required {\n    color: #000;\n}\n\ntr.alt {\n    background: #f6f6f6;\n}\n\n.row1 {\n    background: #fff;\n}\n\n.row2 {\n    background: #f9f9f9;\n}\n\n/* SORTABLE TABLES */\n\nthead th {\n    padding: 5px 10px;\n    line-height: normal;\n    text-transform: uppercase;\n    background: #f6f6f6;\n}\n\nthead th a:link, thead th a:visited {\n    color: #666;\n}\n\nthead th.sorted {\n    background: #eee;\n}\n\nthead th.sorted .text {\n    padding-right: 42px;\n}\n\ntable thead th .text span {\n    padding: 8px 10px;\n    display: block;\n}\n\ntable thead th .text a {\n    display: block;\n    cursor: pointer;\n    padding: 8px 10px;\n}\n\ntable thead th .text a:focus, table thead th .text a:hover {\n    background: #eee;\n}\n\nthead th.sorted a.sortremove {\n    visibility: hidden;\n}\n\ntable thead th.sorted:hover a.sortremove {\n    visibility: visible;\n}\n\ntable thead th.sorted .sortoptions {\n    display: block;\n    padding: 9px 5px 0 5px;\n    float: right;\n    text-align: right;\n}\n\ntable thead th.sorted .sortpriority {\n    font-size: .8em;\n    min-width: 12px;\n    text-align: center;\n    vertical-align: 3px;\n    margin-left: 2px;\n    margin-right: 2px;\n}\n\ntable thead th.sorted .sortoptions a {\n    position: relative;\n    width: 14px;\n    height: 14px;\n    display: inline-block;\n    background: url(../img/sorting-icons.svg) 0 0 no-repeat;\n    background-size: 14px auto;\n}\n\ntable thead th.sorted .sortoptions a.sortremove {\n    background-position: 0 0;\n}\n\ntable thead th.sorted .sortoptions a.sortremove:after {\n    content: '\\\\';\n    position: absolute;\n    top: -6px;\n    left: 3px;\n    font-weight: 200;\n    font-size: 18px;\n    color: #999;\n}\n\ntable thead th.sorted .sortoptions a.sortremove:focus:after,\ntable thead th.sorted .sortoptions a.sortremove:hover:after {\n    color: #447e9b;\n}\n\ntable thead th.sorted .sortoptions a.sortremove:focus,\ntable thead th.sorted .sortoptions a.sortremove:hover {\n    background-position: 0 -14px;\n}\n\ntable thead th.sorted .sortoptions a.ascending {\n    background-position: 0 -28px;\n}\n\ntable thead th.sorted .sortoptions a.ascending:focus,\ntable thead th.sorted .sortoptions a.ascending:hover {\n    background-position: 0 -42px;\n}\n\ntable thead th.sorted .sortoptions a.descending {\n    top: 1px;\n    background-position: 0 -56px;\n}\n\ntable thead th.sorted .sortoptions a.descending:focus,\ntable thead th.sorted .sortoptions a.descending:hover {\n    background-position: 0 -70px;\n}\n\n/* FORM DEFAULTS */\n\ninput, textarea, select, .form-row p, form .button {\n    margin: 2px 0;\n    padding: 2px 3px;\n    vertical-align: middle;\n    font-family: \"Roboto\", \"Lucida Grande\", Verdana, Arial, sans-serif;\n    font-weight: normal;\n    font-size: 13px;\n}\n.form-row div.help {\n    padding: 2px 3px;\n}\n\ntextarea {\n    vertical-align: top;\n}\n\ninput[type=text], input[type=password], input[type=email], input[type=url],\ninput[type=number], textarea, select, .vTextField {\n    border: 1px solid #ccc;\n    border-radius: 4px;\n    padding: 5px 6px;\n    margin-top: 0;\n}\n\ninput[type=text]:focus, input[type=password]:focus, input[type=email]:focus,\ninput[type=url]:focus, input[type=number]:focus, textarea:focus, select:focus,\n.vTextField:focus {\n    border-color: #999;\n}\n\nselect {\n    height: 30px;\n}\n\nselect[multiple] {\n    min-height: 150px;\n}\n\n/* FORM BUTTONS */\n\n.button, input[type=submit], input[type=button], .submit-row input, a.button {\n    background: #79aec8;\n    padding: 10px 15px;\n    border: none;\n    border-radius: 4px;\n    color: #fff;\n    cursor: pointer;\n}\n\na.button {\n    padding: 4px 5px;\n}\n\n.button:active, input[type=submit]:active, input[type=button]:active,\n.button:focus, input[type=submit]:focus, input[type=button]:focus,\n.button:hover, input[type=submit]:hover, input[type=button]:hover {\n    background: #609ab6;\n}\n\n.button[disabled], input[type=submit][disabled], input[type=button][disabled] {\n    opacity: 0.4;\n}\n\n.button.default, input[type=submit].default, .submit-row input.default {\n    float: right;\n    border: none;\n    font-weight: 400;\n    background: #417690;\n}\n\n.button.default:active, input[type=submit].default:active,\n.button.default:focus, input[type=submit].default:focus,\n.button.default:hover, input[type=submit].default:hover {\n    background: #205067;\n}\n\n.button[disabled].default,\ninput[type=submit][disabled].default,\ninput[type=button][disabled].default {\n    opacity: 0.4;\n}\n\n\n/* MODULES */\n\n.module {\n    border: none;\n    margin-bottom: 30px;\n    background: #fff;\n}\n\n.module p, .module ul, .module h3, .module h4, .module dl, .module pre {\n    padding-left: 10px;\n    padding-right: 10px;\n}\n\n.module blockquote {\n    margin-left: 12px;\n}\n\n.module ul, .module ol {\n    margin-left: 1.5em;\n}\n\n.module h3 {\n    margin-top: .6em;\n}\n\n.module h2, .module caption, .inline-group h2 {\n    margin: 0;\n    padding: 8px;\n    font-weight: 400;\n    font-size: 13px;\n    text-align: left;\n    background: #79aec8;\n    color: #fff;\n}\n\n.module caption,\n.inline-group h2 {\n    font-size: 12px;\n    letter-spacing: 0.5px;\n    text-transform: uppercase;\n}\n\n.module table {\n    border-collapse: collapse;\n}\n\n/* MESSAGES & ERRORS */\n\nul.messagelist {\n    padding: 0;\n    margin: 0;\n}\n\nul.messagelist li {\n    display: block;\n    font-weight: 400;\n    font-size: 13px;\n    padding: 10px 10px 10px 65px;\n    margin: 0 0 10px 0;\n    background: #dfd url(../img/icon-yes.svg) 40px 12px no-repeat;\n    background-size: 16px auto;\n    color: #333;\n}\n\nul.messagelist li.warning {\n    background: #ffc url(../img/icon-alert.svg) 40px 14px no-repeat;\n    background-size: 14px auto;\n}\n\nul.messagelist li.error {\n    background: #ffefef url(../img/icon-no.svg) 40px 12px no-repeat;\n    background-size: 16px auto;\n}\n\n.errornote {\n    font-size: 14px;\n    font-weight: 700;\n    display: block;\n    padding: 10px 12px;\n    margin: 0 0 10px 0;\n    color: #ba2121;\n    border: 1px solid #ba2121;\n    border-radius: 4px;\n    background-color: #fff;\n    background-position: 5px 12px;\n}\n\nul.errorlist {\n    margin: 0 0 4px;\n    padding: 0;\n    color: #ba2121;\n    background: #fff;\n}\n\nul.errorlist li {\n    font-size: 13px;\n    display: block;\n    margin-bottom: 4px;\n}\n\nul.errorlist li:first-child {\n    margin-top: 0;\n}\n\nul.errorlist li a {\n    color: inherit;\n    text-decoration: underline;\n}\n\ntd ul.errorlist {\n    margin: 0;\n    padding: 0;\n}\n\ntd ul.errorlist li {\n    margin: 0;\n}\n\n.form-row.errors {\n    margin: 0;\n    border: none;\n    border-bottom: 1px solid #eee;\n    background: none;\n}\n\n.form-row.errors ul.errorlist li {\n    padding-left: 0;\n}\n\n.errors input, .errors select, .errors textarea {\n    border: 1px solid #ba2121;\n}\n\ndiv.system-message {\n    background: #ffc;\n    margin: 10px;\n    padding: 6px 8px;\n    font-size: .8em;\n}\n\ndiv.system-message p.system-message-title {\n    padding: 4px 5px 4px 25px;\n    margin: 0;\n    color: #c11;\n    background: #ffefef url(../img/icon-no.svg) 5px 5px no-repeat;\n}\n\n.description {\n    font-size: 12px;\n    padding: 5px 0 0 12px;\n}\n\n/* BREADCRUMBS */\n\ndiv.breadcrumbs {\n    background: #79aec8;\n    padding: 10px 40px;\n    border: none;\n    font-size: 14px;\n    color: #c4dce8;\n    text-align: left;\n}\n\ndiv.breadcrumbs a {\n    color: #fff;\n}\n\ndiv.breadcrumbs a:focus, div.breadcrumbs a:hover {\n    color: #c4dce8;\n}\n\n/* ACTION ICONS */\n\n.addlink {\n    padding-left: 16px;\n    background: url(../img/icon-addlink.svg) 0 1px no-repeat;\n}\n\n.changelink, .inlinechangelink {\n    padding-left: 16px;\n    background: url(../img/icon-changelink.svg) 0 1px no-repeat;\n}\n\n.deletelink {\n    padding-left: 16px;\n    background: url(../img/icon-deletelink.svg) 0 1px no-repeat;\n}\n\na.deletelink:link, a.deletelink:visited {\n    color: #CC3434;\n}\n\na.deletelink:focus, a.deletelink:hover {\n    color: #993333;\n    text-decoration: none;\n}\n\n/* OBJECT TOOLS */\n\n.object-tools {\n    font-size: 10px;\n    font-weight: bold;\n    padding-left: 0;\n    float: right;\n    position: relative;\n    margin-top: -48px;\n}\n\n.form-row .object-tools {\n    margin-top: 5px;\n    margin-bottom: 5px;\n    float: none;\n    height: 2em;\n    padding-left: 3.5em;\n}\n\n.object-tools li {\n    display: block;\n    float: left;\n    margin-left: 5px;\n    height: 16px;\n}\n\n.object-tools a {\n    border-radius: 15px;\n}\n\n.object-tools a:link, .object-tools a:visited {\n    display: block;\n    float: left;\n    padding: 3px 12px;\n    background: #999;\n    font-weight: 400;\n    font-size: 11px;\n    text-transform: uppercase;\n    letter-spacing: 0.5px;\n    color: #fff;\n}\n\n.object-tools a:focus, .object-tools a:hover {\n    background-color: #417690;\n}\n\n.object-tools a:focus{\n    text-decoration: none;\n}\n\n.object-tools a.viewsitelink, .object-tools a.golink,.object-tools a.addlink {\n    background-repeat: no-repeat;\n    background-position: right 7px center;\n    padding-right: 26px;\n}\n\n.object-tools a.viewsitelink, .object-tools a.golink {\n    background-image: url(../img/tooltag-arrowright.svg);\n}\n\n.object-tools a.addlink {\n    background-image: url(../img/tooltag-add.svg);\n}\n\n/* OBJECT HISTORY */\n\ntable#change-history {\n    width: 100%;\n}\n\ntable#change-history tbody th {\n    width: 16em;\n}\n\n/* PAGE STRUCTURE */\n\n#container {\n    position: relative;\n    width: 100%;\n    min-width: 980px;\n    padding: 0;\n}\n\n#content {\n    padding: 20px 40px;\n}\n\n.dashboard #content {\n    width: 600px;\n}\n\n#content-main {\n    float: left;\n    width: 100%;\n}\n\n#content-related {\n    float: right;\n    width: 260px;\n    position: relative;\n    margin-right: -300px;\n}\n\n#footer {\n    clear: both;\n    padding: 10px;\n}\n\n/* COLUMN TYPES */\n\n.colMS {\n    margin-right: 300px;\n}\n\n.colSM {\n    margin-left: 300px;\n}\n\n.colSM #content-related {\n    float: left;\n    margin-right: 0;\n    margin-left: -300px;\n}\n\n.colSM #content-main {\n    float: right;\n}\n\n.popup .colM {\n    width: auto;\n}\n\n/* HEADER */\n\n#header {\n    width: auto;\n    height: 40px;\n    padding: 10px 40px;\n    background: #417690;\n    line-height: 40px;\n    color: #ffc;\n    overflow: hidden;\n}\n\n#header a:link, #header a:visited {\n    color: #fff;\n}\n\n#header a:focus , #header a:hover {\n    text-decoration: underline;\n}\n\n#branding {\n    float: left;\n}\n\n#branding h1 {\n    padding: 0;\n    margin: 0 20px 0 0;\n    font-weight: 300;\n    font-size: 24px;\n    color: #f5dd5d;\n}\n\n#branding h1, #branding h1 a:link, #branding h1 a:visited {\n    color: #f5dd5d;\n}\n\n#branding h2 {\n    padding: 0 10px;\n    font-size: 14px;\n    margin: -8px 0 8px 0;\n    font-weight: normal;\n    color: #ffc;\n}\n\n#branding a:hover {\n    text-decoration: none;\n}\n\n#user-tools {\n    float: right;\n    padding: 0;\n    margin: 0 0 0 20px;\n    font-weight: 300;\n    font-size: 11px;\n    letter-spacing: 0.5px;\n    text-transform: uppercase;\n    text-align: right;\n}\n\n#user-tools a {\n    border-bottom: 1px solid rgba(255, 255, 255, 0.25);\n}\n\n#user-tools a:focus, #user-tools a:hover {\n    text-decoration: none;\n    border-bottom-color: #79aec8;\n    color: #79aec8;\n}\n\n/* SIDEBAR */\n\n#content-related {\n    background: #f8f8f8;\n}\n\n#content-related .module {\n    background: none;\n}\n\n#content-related h3 {\n    font-size: 14px;\n    color: #666;\n    padding: 0 16px;\n    margin: 0 0 16px;\n}\n\n#content-related h4 {\n    font-size: 13px;\n}\n\n#content-related p {\n    padding-left: 16px;\n    padding-right: 16px;\n}\n\n#content-related .actionlist {\n    padding: 0;\n    margin: 16px;\n}\n\n#content-related .actionlist li {\n    line-height: 1.2;\n    margin-bottom: 10px;\n    padding-left: 18px;\n}\n\n#content-related .module h2 {\n    background: none;\n    padding: 16px;\n    margin-bottom: 16px;\n    border-bottom: 1px solid #eaeaea;\n    font-size: 18px;\n    color: #333;\n}\n\n.delete-confirmation form input[type=\"submit\"] {\n    background: #ba2121;\n    border-radius: 4px;\n    padding: 10px 15px;\n    color: #fff;\n}\n\n.delete-confirmation form input[type=\"submit\"]:active,\n.delete-confirmation form input[type=\"submit\"]:focus,\n.delete-confirmation form input[type=\"submit\"]:hover {\n    background: #a41515;\n}\n\n.delete-confirmation form .cancel-link {\n    display: inline-block;\n    vertical-align: middle;\n    height: 15px;\n    line-height: 15px;\n    background: #ddd;\n    border-radius: 4px;\n    padding: 10px 15px;\n    color: #333;\n    margin: 0 0 0 10px;\n}\n\n.delete-confirmation form .cancel-link:active,\n.delete-confirmation form .cancel-link:focus,\n.delete-confirmation form .cancel-link:hover {\n    background: #ccc;\n}\n\n/* POPUP */\n.popup #content {\n    padding: 20px;\n}\n\n.popup #container {\n    min-width: 0;\n}\n\n.popup #header {\n    padding: 10px 20px;\n}\n"
  },
  {
    "path": "static_cdn/static_root/admin/css/changelists.css",
    "content": "/* CHANGELISTS */\n\n#changelist {\n    position: relative;\n    width: 100%;\n}\n\n#changelist table {\n    width: 100%;\n}\n\n.change-list .hiddenfields { display:none; }\n\n.change-list .filtered table {\n    border-right: none;\n}\n\n.change-list .filtered {\n    min-height: 400px;\n}\n\n.change-list .filtered .results, .change-list .filtered .paginator,\n.filtered #toolbar, .filtered div.xfull {\n    margin-right: 280px;\n    width: auto;\n}\n\n.change-list .filtered table tbody th {\n    padding-right: 1em;\n}\n\n#changelist-form .results {\n  overflow-x: auto;\n}\n\n#changelist .toplinks {\n    border-bottom: 1px solid #ddd;\n}\n\n#changelist .paginator {\n    color: #666;\n    border-bottom: 1px solid #eee;\n    background: #fff;\n    overflow: hidden;\n}\n\n/* CHANGELIST TABLES */\n\n#changelist table thead th {\n    padding: 0;\n    white-space: nowrap;\n    vertical-align: middle;\n}\n\n#changelist table thead th.action-checkbox-column {\n    width: 1.5em;\n    text-align: center;\n}\n\n#changelist table tbody td.action-checkbox {\n    text-align: center;\n}\n\n#changelist table tfoot {\n    color: #666;\n}\n\n/* TOOLBAR */\n\n#changelist #toolbar {\n    padding: 8px 10px;\n    margin-bottom: 15px;\n    border-top: 1px solid #eee;\n    border-bottom: 1px solid #eee;\n    background: #f8f8f8;\n    color: #666;\n}\n\n#changelist #toolbar form input {\n    border-radius: 4px;\n    font-size: 14px;\n    padding: 5px;\n    color: #333;\n}\n\n#changelist #toolbar form #searchbar {\n    height: 19px;\n    border: 1px solid #ccc;\n    padding: 2px 5px;\n    margin: 0;\n    vertical-align: top;\n    font-size: 13px;\n}\n\n#changelist #toolbar form #searchbar:focus {\n    border-color: #999;\n}\n\n#changelist #toolbar form input[type=\"submit\"] {\n    border: 1px solid #ccc;\n    padding: 2px 10px;\n    margin: 0;\n    vertical-align: middle;\n    background: #fff;\n    box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset;\n    cursor: pointer;\n    color: #333;\n}\n\n#changelist #toolbar form input[type=\"submit\"]:focus,\n#changelist #toolbar form input[type=\"submit\"]:hover {\n    border-color: #999;\n}\n\n#changelist #changelist-search img {\n    vertical-align: middle;\n    margin-right: 4px;\n}\n\n/* FILTER COLUMN */\n\n#changelist-filter {\n    position: absolute;\n    top: 0;\n    right: 0;\n    z-index: 1000;\n    width: 240px;\n    background: #f8f8f8;\n    border-left: none;\n    margin: 0;\n}\n\n#changelist-filter h2 {\n    font-size: 14px;\n    text-transform: uppercase;\n    letter-spacing: 0.5px;\n    padding: 5px 15px;\n    margin-bottom: 12px;\n    border-bottom: none;\n}\n\n#changelist-filter h3 {\n    font-weight: 400;\n    font-size: 14px;\n    padding: 0 15px;\n    margin-bottom: 10px;\n}\n\n#changelist-filter ul {\n    margin: 5px 0;\n    padding: 0 15px 15px;\n    border-bottom: 1px solid #eaeaea;\n}\n\n#changelist-filter ul:last-child {\n    border-bottom: none;\n    padding-bottom: none;\n}\n\n#changelist-filter li {\n    list-style-type: none;\n    margin-left: 0;\n    padding-left: 0;\n}\n\n#changelist-filter a {\n    display: block;\n    color: #999;\n    text-overflow: ellipsis;\n    overflow-x: hidden;\n}\n\n#changelist-filter li.selected {\n    border-left: 5px solid #eaeaea;\n    padding-left: 10px;\n    margin-left: -15px;\n}\n\n#changelist-filter li.selected a {\n    color: #5b80b2;\n}\n\n#changelist-filter a:focus, #changelist-filter a:hover,\n#changelist-filter li.selected a:focus,\n#changelist-filter li.selected a:hover {\n    color: #036;\n}\n\n/* DATE DRILLDOWN */\n\n.change-list ul.toplinks {\n    display: block;\n    float: left;\n    padding: 0;\n    margin: 0;\n    width: 100%;\n}\n\n.change-list ul.toplinks li {\n    padding: 3px 6px;\n    font-weight: bold;\n    list-style-type: none;\n    display: inline-block;\n}\n\n.change-list ul.toplinks .date-back a {\n    color: #999;\n}\n\n.change-list ul.toplinks .date-back a:focus,\n.change-list ul.toplinks .date-back a:hover {\n    color: #036;\n}\n\n/* PAGINATOR */\n\n.paginator {\n    font-size: 13px;\n    padding-top: 10px;\n    padding-bottom: 10px;\n    line-height: 22px;\n    margin: 0;\n    border-top: 1px solid #ddd;\n}\n\n.paginator a:link, .paginator a:visited {\n    padding: 2px 6px;\n    background: #79aec8;\n    text-decoration: none;\n    color: #fff;\n}\n\n.paginator a.showall {\n    padding: 0;\n    border: none;\n    background: none;\n    color: #5b80b2;\n}\n\n.paginator a.showall:focus, .paginator a.showall:hover {\n    background: none;\n    color: #036;\n}\n\n.paginator .end {\n    margin-right: 6px;\n}\n\n.paginator .this-page {\n    padding: 2px 6px;\n    font-weight: bold;\n    font-size: 13px;\n    vertical-align: top;\n}\n\n.paginator a:focus, .paginator a:hover {\n    color: white;\n    background: #036;\n}\n\n/* ACTIONS */\n\n.filtered .actions {\n    margin-right: 280px;\n    border-right: none;\n}\n\n#changelist table input {\n    margin: 0;\n    vertical-align: baseline;\n}\n\n#changelist table tbody tr.selected {\n    background-color: #FFFFCC;\n}\n\n#changelist .actions {\n    padding: 10px;\n    background: #fff;\n    border-top: none;\n    border-bottom: none;\n    line-height: 24px;\n    color: #999;\n}\n\n#changelist .actions.selected {\n    background: #fffccf;\n    border-top: 1px solid #fffee8;\n    border-bottom: 1px solid #edecd6;\n}\n\n#changelist .actions span.all,\n#changelist .actions span.action-counter,\n#changelist .actions span.clear,\n#changelist .actions span.question {\n    font-size: 13px;\n    margin: 0 0.5em;\n    display: none;\n}\n\n#changelist .actions:last-child {\n    border-bottom: none;\n}\n\n#changelist .actions select {\n    vertical-align: top;\n    height: 24px;\n    background: none;\n    color: #000;\n    border: 1px solid #ccc;\n    border-radius: 4px;\n    font-size: 14px;\n    padding: 0 0 0 4px;\n    margin: 0;\n    margin-left: 10px;\n}\n\n#changelist .actions select:focus {\n    border-color: #999;\n}\n\n#changelist .actions label {\n    display: inline-block;\n    vertical-align: middle;\n    font-size: 13px;\n}\n\n#changelist .actions .button {\n    font-size: 13px;\n    border: 1px solid #ccc;\n    border-radius: 4px;\n    background: #fff;\n    box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset;\n    cursor: pointer;\n    height: 24px;\n    line-height: 1;\n    padding: 4px 8px;\n    margin: 0;\n    color: #333;\n}\n\n#changelist .actions .button:focus, #changelist .actions .button:hover {\n    border-color: #999;\n}\n"
  },
  {
    "path": "static_cdn/static_root/admin/css/dashboard.css",
    "content": "/* DASHBOARD */\n\n.dashboard .module table th {\n    width: 100%;\n}\n\n.dashboard .module table td {\n    white-space: nowrap;\n}\n\n.dashboard .module table td a {\n    display: block;\n    padding-right: .6em;\n}\n\n/* RECENT ACTIONS MODULE */\n\n.module ul.actionlist {\n    margin-left: 0;\n}\n\nul.actionlist li {\n    list-style-type: none;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    -o-text-overflow: ellipsis;\n}\n"
  },
  {
    "path": "static_cdn/static_root/admin/css/fonts.css",
    "content": "@font-face {\n    font-family: 'Roboto';\n    src: url('../fonts/Roboto-Bold-webfont.woff');\n    font-weight: 700;\n    font-style: normal;\n}\n\n@font-face {\n    font-family: 'Roboto';\n    src: url('../fonts/Roboto-Regular-webfont.woff');\n    font-weight: 400;\n    font-style: normal;\n}\n\n@font-face {\n    font-family: 'Roboto';\n    src: url('../fonts/Roboto-Light-webfont.woff');\n    font-weight: 300;\n    font-style: normal;\n}\n"
  },
  {
    "path": "static_cdn/static_root/admin/css/forms.css",
    "content": "@import url('widgets.css');\n\n/* FORM ROWS */\n\n.form-row {\n    overflow: hidden;\n    padding: 10px;\n    font-size: 13px;\n    border-bottom: 1px solid #eee;\n}\n\n.form-row img, .form-row input {\n    vertical-align: middle;\n}\n\n.form-row label input[type=\"checkbox\"] {\n    margin-top: 0;\n    vertical-align: 0;\n}\n\nform .form-row p {\n    padding-left: 0;\n}\n\n.hidden {\n    display: none;\n}\n\n/* FORM LABELS */\n\nlabel {\n    font-weight: normal;\n    color: #666;\n    font-size: 13px;\n}\n\n.required label, label.required {\n    font-weight: bold;\n    color: #333;\n}\n\n/* RADIO BUTTONS */\n\nform ul.radiolist li {\n    list-style-type: none;\n}\n\nform ul.radiolist label {\n    float: none;\n    display: inline;\n}\n\nform ul.radiolist input[type=\"radio\"] {\n    margin: -2px 4px 0 0;\n    padding: 0;\n}\n\nform ul.inline {\n    margin-left: 0;\n    padding: 0;\n}\n\nform ul.inline li {\n    float: left;\n    padding-right: 7px;\n}\n\n/* ALIGNED FIELDSETS */\n\n.aligned label {\n    display: block;\n    padding: 4px 10px 0 0;\n    float: left;\n    width: 160px;\n    word-wrap: break-word;\n    line-height: 1;\n}\n\n.aligned label:not(.vCheckboxLabel):after {\n    content: '';\n    display: inline-block;\n    vertical-align: middle;\n    height: 26px;\n}\n\n.aligned label + p, .aligned label + div.help, .aligned label + div.readonly {\n    padding: 6px 0;\n    margin-top: 0;\n    margin-bottom: 0;\n    margin-left: 170px;\n}\n\n.aligned ul label {\n    display: inline;\n    float: none;\n    width: auto;\n}\n\n.aligned .form-row input {\n    margin-bottom: 0;\n}\n\n.colMS .aligned .vLargeTextField, .colMS .aligned .vXMLLargeTextField {\n    width: 350px;\n}\n\nform .aligned ul {\n    margin-left: 160px;\n    padding-left: 10px;\n}\n\nform .aligned ul.radiolist {\n    display: inline-block;\n    margin: 0;\n    padding: 0;\n}\n\nform .aligned p.help,\nform .aligned div.help {\n    clear: left;\n    margin-top: 0;\n    margin-left: 160px;\n    padding-left: 10px;\n}\n\nform .aligned label + p.help,\nform .aligned label + div.help {\n    margin-left: 0;\n    padding-left: 0;\n}\n\nform .aligned p.help:last-child,\nform .aligned div.help:last-child {\n    margin-bottom: 0;\n    padding-bottom: 0;\n}\n\nform .aligned input + p.help,\nform .aligned textarea + p.help,\nform .aligned select + p.help,\nform .aligned input + div.help,\nform .aligned textarea + div.help,\nform .aligned select + div.help {\n    margin-left: 160px;\n    padding-left: 10px;\n}\n\nform .aligned ul li {\n    list-style: none;\n}\n\nform .aligned table p {\n    margin-left: 0;\n    padding-left: 0;\n}\n\n.aligned .vCheckboxLabel {\n    float: none;\n    width: auto;\n    display: inline-block;\n    vertical-align: -3px;\n    padding: 0 0 5px 5px;\n}\n\n.aligned .vCheckboxLabel + p.help,\n.aligned .vCheckboxLabel + div.help {\n    margin-top: -4px;\n}\n\n.colM .aligned .vLargeTextField, .colM .aligned .vXMLLargeTextField {\n    width: 610px;\n}\n\n.checkbox-row p.help,\n.checkbox-row div.help {\n    margin-left: 0;\n    padding-left: 0;\n}\n\nfieldset .field-box {\n    float: left;\n    margin-right: 20px;\n}\n\n/* WIDE FIELDSETS */\n\n.wide label {\n    width: 200px;\n}\n\nform .wide p,\nform .wide input + p.help,\nform .wide input + div.help {\n    margin-left: 200px;\n}\n\nform .wide p.help,\nform .wide div.help {\n    padding-left: 38px;\n}\n\nform div.help ul {\n    padding-left: 0;\n    margin-left: 0;\n}\n\n.colM fieldset.wide .vLargeTextField, .colM fieldset.wide .vXMLLargeTextField {\n    width: 450px;\n}\n\n/* COLLAPSED FIELDSETS */\n\nfieldset.collapsed * {\n    display: none;\n}\n\nfieldset.collapsed h2, fieldset.collapsed {\n    display: block;\n}\n\nfieldset.collapsed {\n    border: 1px solid #eee;\n    border-radius: 4px;\n    overflow: hidden;\n}\n\nfieldset.collapsed h2 {\n    background: #f8f8f8;\n    color: #666;\n}\n\nfieldset .collapse-toggle {\n    color: #fff;\n}\n\nfieldset.collapsed .collapse-toggle {\n    background: transparent;\n    display: inline;\n    color: #447e9b;\n}\n\n/* MONOSPACE TEXTAREAS */\n\nfieldset.monospace textarea {\n    font-family: \"Bitstream Vera Sans Mono\", Monaco, \"Courier New\", Courier, monospace;\n}\n\n/* SUBMIT ROW */\n\n.submit-row {\n    padding: 12px 14px;\n    margin: 0 0 20px;\n    background: #f8f8f8;\n    border: 1px solid #eee;\n    border-radius: 4px;\n    text-align: right;\n    overflow: hidden;\n}\n\nbody.popup .submit-row {\n    overflow: auto;\n}\n\n.submit-row input {\n    height: 35px;\n    line-height: 15px;\n    margin: 0 0 0 5px;\n}\n\n.submit-row input.default {\n    margin: 0 0 0 8px;\n    text-transform: uppercase;\n}\n\n.submit-row p {\n    margin: 0.3em;\n}\n\n.submit-row p.deletelink-box {\n    float: left;\n    margin: 0;\n}\n\n.submit-row a.deletelink {\n    display: block;\n    background: #ba2121;\n    border-radius: 4px;\n    padding: 10px 15px;\n    height: 15px;\n    line-height: 15px;\n    color: #fff;\n}\n\n.submit-row a.deletelink:focus,\n.submit-row a.deletelink:hover,\n.submit-row a.deletelink:active {\n    background: #a41515;\n}\n\n/* CUSTOM FORM FIELDS */\n\n.vSelectMultipleField {\n    vertical-align: top;\n}\n\n.vCheckboxField {\n    border: none;\n}\n\n.vDateField, .vTimeField {\n    margin-right: 2px;\n    margin-bottom: 4px;\n}\n\n.vDateField {\n    min-width: 6.85em;\n}\n\n.vTimeField {\n    min-width: 4.7em;\n}\n\n.vURLField {\n    width: 30em;\n}\n\n.vLargeTextField, .vXMLLargeTextField {\n    width: 48em;\n}\n\n.flatpages-flatpage #id_content {\n    height: 40.2em;\n}\n\n.module table .vPositiveSmallIntegerField {\n    width: 2.2em;\n}\n\n.vTextField {\n    width: 20em;\n}\n\n.vIntegerField {\n    width: 5em;\n}\n\n.vBigIntegerField {\n    width: 10em;\n}\n\n.vForeignKeyRawIdAdminField {\n    width: 5em;\n}\n\n/* INLINES */\n\n.inline-group {\n    padding: 0;\n    margin: 0 0 30px;\n}\n\n.inline-group thead th {\n    padding: 8px 10px;\n}\n\n.inline-group .aligned label {\n    width: 160px;\n}\n\n.inline-related {\n    position: relative;\n}\n\n.inline-related h3 {\n    margin: 0;\n    color: #666;\n    padding: 5px;\n    font-size: 13px;\n    background: #f8f8f8;\n    border-top: 1px solid #eee;\n    border-bottom: 1px solid #eee;\n}\n\n.inline-related h3 span.delete {\n    float: right;\n}\n\n.inline-related h3 span.delete label {\n    margin-left: 2px;\n    font-size: 11px;\n}\n\n.inline-related fieldset {\n    margin: 0;\n    background: #fff;\n    border: none;\n    width: 100%;\n}\n\n.inline-related fieldset.module h3 {\n    margin: 0;\n    padding: 2px 5px 3px 5px;\n    font-size: 11px;\n    text-align: left;\n    font-weight: bold;\n    background: #bcd;\n    color: #fff;\n}\n\n.inline-group .tabular fieldset.module {\n    border: none;\n}\n\n.inline-related.tabular fieldset.module table {\n    width: 100%;\n}\n\n.last-related fieldset {\n    border: none;\n}\n\n.inline-group .tabular tr.has_original td {\n    padding-top: 2em;\n}\n\n.inline-group .tabular tr td.original {\n    padding: 2px 0 0 0;\n    width: 0;\n    _position: relative;\n}\n\n.inline-group .tabular th.original {\n    width: 0px;\n    padding: 0;\n}\n\n.inline-group .tabular td.original p {\n    position: absolute;\n    left: 0;\n    height: 1.1em;\n    padding: 2px 9px;\n    overflow: hidden;\n    font-size: 9px;\n    font-weight: bold;\n    color: #666;\n    _width: 700px;\n}\n\n.inline-group ul.tools {\n    padding: 0;\n    margin: 0;\n    list-style: none;\n}\n\n.inline-group ul.tools li {\n    display: inline;\n    padding: 0 5px;\n}\n\n.inline-group div.add-row,\n.inline-group .tabular tr.add-row td {\n    color: #666;\n    background: #f8f8f8;\n    padding: 8px 10px;\n    border-bottom: 1px solid #eee;\n}\n\n.inline-group .tabular tr.add-row td {\n    padding: 8px 10px;\n    border-bottom: 1px solid #eee;\n}\n\n.inline-group ul.tools a.add,\n.inline-group div.add-row a,\n.inline-group .tabular tr.add-row td a {\n    background: url(../img/icon-addlink.svg) 0 1px no-repeat;\n    padding-left: 16px;\n    font-size: 12px;\n}\n\n.empty-form {\n    display: none;\n}\n\n/* RELATED FIELD ADD ONE / LOOKUP */\n\n.add-another, .related-lookup {\n    margin-left: 5px;\n    display: inline-block;\n    vertical-align: middle;\n    background-repeat: no-repeat;\n    background-size: 14px;\n}\n\n.add-another {\n    width: 16px;\n    height: 16px;\n    background-image: url(../img/icon-addlink.svg);\n}\n\n.related-lookup {\n    width: 16px;\n    height: 16px;\n    background-image: url(../img/search.svg);\n}\n\nform .related-widget-wrapper ul {\n    display: inline-block;\n    margin-left: 0;\n    padding-left: 0;\n}\n\n.clearable-file-input input {\n    margin-top: 0;\n}\n"
  },
  {
    "path": "static_cdn/static_root/admin/css/login.css",
    "content": "/* LOGIN FORM */\n\nbody.login {\n    background: #f8f8f8;\n}\n\n.login #header {\n    height: auto;\n    padding: 5px 16px;\n}\n\n.login #header h1 {\n    font-size: 18px;\n}\n\n.login #header h1 a {\n    color: #fff;\n}\n\n.login #content {\n    padding: 20px 20px 0;\n}\n\n.login #container {\n    background: #fff;\n    border: 1px solid #eaeaea;\n    border-radius: 4px;\n    overflow: hidden;\n    width: 28em;\n    min-width: 300px;\n    margin: 100px auto;\n}\n\n.login #content-main {\n    width: 100%;\n}\n\n.login .form-row {\n    padding: 4px 0;\n    float: left;\n    width: 100%;\n    border-bottom: none;\n}\n\n.login .form-row label {\n    padding-right: 0.5em;\n    line-height: 2em;\n    font-size: 1em;\n    clear: both;\n    color: #333;\n}\n\n.login .form-row #id_username, .login .form-row #id_password {\n    clear: both;\n    padding: 8px;\n    width: 100%;\n    -webkit-box-sizing: border-box;\n       -moz-box-sizing: border-box;\n            box-sizing: border-box;\n}\n\n.login span.help {\n    font-size: 10px;\n    display: block;\n}\n\n.login .submit-row {\n    clear: both;\n    padding: 1em 0 0 9.4em;\n    margin: 0;\n    border: none;\n    background: none;\n    text-align: left;\n}\n\n.login .password-reset-link {\n    text-align: center;\n}\n"
  },
  {
    "path": "static_cdn/static_root/admin/css/rtl.css",
    "content": "body {\n    direction: rtl;\n}\n\n/* LOGIN */\n\n.login .form-row {\n    float: right;\n}\n\n.login .form-row label {\n    float: right;\n    padding-left: 0.5em;\n    padding-right: 0;\n    text-align: left;\n}\n\n.login .submit-row {\n    clear: both;\n    padding: 1em 9.4em 0 0;\n}\n\n/* GLOBAL */\n\nth {\n    text-align: right;\n}\n\n.module h2, .module caption {\n    text-align: right;\n}\n\n.module ul, .module ol {\n    margin-left: 0;\n    margin-right: 1.5em;\n}\n\n.addlink, .changelink {\n    padding-left: 0;\n    padding-right: 16px;\n    background-position: 100% 1px;\n}\n\n.deletelink {\n    padding-left: 0;\n    padding-right: 16px;\n    background-position: 100% 1px;\n}\n\n.object-tools {\n    float: left;\n}\n\nthead th:first-child,\ntfoot td:first-child {\n    border-left: none;\n}\n\n/* LAYOUT */\n\n#user-tools {\n    right: auto;\n    left: 0;\n    text-align: left;\n}\n\ndiv.breadcrumbs {\n    text-align: right;\n}\n\n#content-main {\n    float: right;\n}\n\n#content-related {\n    float: left;\n    margin-left: -300px;\n    margin-right: auto;\n}\n\n.colMS {\n    margin-left: 300px;\n    margin-right: 0;\n}\n\n/* SORTABLE TABLES */\n\ntable thead th.sorted .sortoptions {\n   float: left;\n}\n\nthead th.sorted .text {\n    padding-right: 0;\n    padding-left: 42px;\n}\n\n/* dashboard styles */\n\n.dashboard .module table td a {\n    padding-left: .6em;\n    padding-right: 16px;\n}\n\n/* changelists styles */\n\n.change-list .filtered table {\n    border-left: none;\n    border-right: 0px none;\n}\n\n#changelist-filter {\n    right: auto;\n    left: 0;\n    border-left: none;\n    border-right: none;\n}\n\n.change-list .filtered .results, .change-list .filtered .paginator, .filtered #toolbar, .filtered div.xfull {\n    margin-right: 0;\n    margin-left: 280px;\n}\n\n#changelist-filter li.selected {\n    border-left: none;\n    padding-left: 10px;\n    margin-left: 0;\n    border-right: 5px solid #eaeaea;\n    padding-right: 10px;\n    margin-right: -15px;\n}\n\n.filtered .actions {\n    margin-left: 280px;\n    margin-right: 0;\n}\n\n#changelist table tbody td:first-child, #changelist table tbody th:first-child {\n    border-right: none;\n    border-left: none;\n}\n\n/* FORMS */\n\n.aligned label {\n    padding: 0 0 3px 1em;\n    float: right;\n}\n\n.submit-row {\n    text-align: left\n}\n\n.submit-row p.deletelink-box {\n    float: right;\n}\n\n.submit-row input.default {\n    margin-left: 0;\n}\n\n.vDateField, .vTimeField {\n    margin-left: 2px;\n}\n\n.aligned .form-row input {\n    margin-left: 5px;\n}\n\nform .aligned p.help, form .aligned div.help {\n    clear: right;\n}\n\nform ul.inline li {\n    float: right;\n    padding-right: 0;\n    padding-left: 7px;\n}\n\ninput[type=submit].default, .submit-row input.default {\n    float: left;\n}\n\nfieldset .field-box {\n    float: right;\n    margin-left: 20px;\n    margin-right: 0;\n}\n\n.errorlist li {\n    background-position: 100% 12px;\n    padding: 0;\n}\n\n.errornote {\n    background-position: 100% 12px;\n    padding: 10px 12px;\n}\n\n/* WIDGETS */\n\n.calendarnav-previous {\n    top: 0;\n    left: auto;\n    right: 10px;\n}\n\n.calendarnav-next {\n    top: 0;\n    right: auto;\n    left: 10px;\n}\n\n.calendar caption, .calendarbox h2 {\n    text-align: center;\n}\n\n.selector {\n    float: right;\n}\n\n.selector .selector-filter {\n    text-align: right;\n}\n\n.inline-deletelink {\n    float: left;\n}\n\nform .form-row p.datetime {\n    overflow: hidden;\n}\n\n.related-widget-wrapper {\n    float: right;\n}\n\n/* MISC */\n\n.inline-related h2, .inline-group h2 {\n    text-align: right\n}\n\n.inline-related h3 span.delete {\n    padding-right: 20px;\n    padding-left: inherit;\n    left: 10px;\n    right: inherit;\n    float:left;\n}\n\n.inline-related h3 span.delete label {\n    margin-left: inherit;\n    margin-right: 2px;\n}\n\n/* IE7 specific bug fixes */\n\ndiv.colM {\n    position: relative;\n}\n\n.submit-row input {\n    float: left;\n}\n"
  },
  {
    "path": "static_cdn/static_root/admin/css/widgets.css",
    "content": "/* SELECTOR (FILTER INTERFACE) */\n\n.selector {\n    width: 800px;\n    float: left;\n}\n\n.selector select {\n    width: 380px;\n    height: 17.2em;\n}\n\n.selector-available, .selector-chosen {\n    float: left;\n    width: 380px;\n    text-align: center;\n    margin-bottom: 5px;\n}\n\n.selector-chosen select {\n    border-top: none;\n}\n\n.selector-available h2, .selector-chosen h2 {\n    border: 1px solid #ccc;\n    border-radius: 4px 4px 0 0;\n}\n\n.selector-chosen h2 {\n    background: #79aec8;\n    color: #fff;\n}\n\n.selector .selector-available h2 {\n    background: #f8f8f8;\n    color: #666;\n}\n\n.selector .selector-filter {\n    background: white;\n    border: 1px solid #ccc;\n    border-width: 0 1px;\n    padding: 8px;\n    color: #999;\n    font-size: 10px;\n    margin: 0;\n    text-align: left;\n}\n\n.selector .selector-filter label,\n.inline-group .aligned .selector .selector-filter label {\n    float: left;\n    margin: 7px 0 0;\n    width: 18px;\n    height: 18px;\n    padding: 0;\n    overflow: hidden;\n    line-height: 1;\n}\n\n.selector .selector-available input {\n    width: 320px;\n    margin-left: 8px;\n}\n\n.selector ul.selector-chooser {\n    float: left;\n    width: 22px;\n    background-color: #eee;\n    border-radius: 10px;\n    margin: 10em 5px 0 5px;\n    padding: 0;\n}\n\n.selector-chooser li {\n    margin: 0;\n    padding: 3px;\n    list-style-type: none;\n}\n\n.selector select {\n    padding: 0 10px;\n    margin: 0 0 10px;\n    border-radius: 0 0 4px 4px;\n}\n\n.selector-add, .selector-remove {\n    width: 16px;\n    height: 16px;\n    display: block;\n    text-indent: -3000px;\n    overflow: hidden;\n    cursor: default;\n    opacity: 0.3;\n}\n\n.active.selector-add, .active.selector-remove {\n    opacity: 1;\n}\n\n.active.selector-add:hover, .active.selector-remove:hover {\n    cursor: pointer;\n}\n\n.selector-add {\n    background: url(../img/selector-icons.svg) 0 -96px no-repeat;\n}\n\n.active.selector-add:focus, .active.selector-add:hover {\n    background-position: 0 -112px;\n}\n\n.selector-remove {\n    background: url(../img/selector-icons.svg) 0 -64px no-repeat;\n}\n\n.active.selector-remove:focus, .active.selector-remove:hover {\n    background-position: 0 -80px;\n}\n\na.selector-chooseall, a.selector-clearall {\n    display: inline-block;\n    height: 16px;\n    text-align: left;\n    margin: 1px auto 3px;\n    overflow: hidden;\n    font-weight: bold;\n    line-height: 16px;\n    color: #666;\n    text-decoration: none;\n    opacity: 0.3;\n}\n\na.active.selector-chooseall:focus, a.active.selector-clearall:focus,\na.active.selector-chooseall:hover, a.active.selector-clearall:hover {\n    color: #447e9b;\n}\n\na.active.selector-chooseall, a.active.selector-clearall {\n    opacity: 1;\n}\n\na.active.selector-chooseall:hover, a.active.selector-clearall:hover {\n    cursor: pointer;\n}\n\na.selector-chooseall {\n    padding: 0 18px 0 0;\n    background: url(../img/selector-icons.svg) right -160px no-repeat;\n    cursor: default;\n}\n\na.active.selector-chooseall:focus, a.active.selector-chooseall:hover {\n    background-position: 100% -176px;\n}\n\na.selector-clearall {\n    padding: 0 0 0 18px;\n    background: url(../img/selector-icons.svg) 0 -128px no-repeat;\n    cursor: default;\n}\n\na.active.selector-clearall:focus, a.active.selector-clearall:hover {\n    background-position: 0 -144px;\n}\n\n/* STACKED SELECTORS */\n\n.stacked {\n    float: left;\n    width: 490px;\n}\n\n.stacked select {\n    width: 480px;\n    height: 10.1em;\n}\n\n.stacked .selector-available, .stacked .selector-chosen {\n    width: 480px;\n}\n\n.stacked .selector-available {\n    margin-bottom: 0;\n}\n\n.stacked .selector-available input {\n    width: 422px;\n}\n\n.stacked ul.selector-chooser {\n    height: 22px;\n    width: 50px;\n    margin: 0 0 10px 40%;\n    background-color: #eee;\n    border-radius: 10px;\n}\n\n.stacked .selector-chooser li {\n    float: left;\n    padding: 3px 3px 3px 5px;\n}\n\n.stacked .selector-chooseall, .stacked .selector-clearall {\n    display: none;\n}\n\n.stacked .selector-add {\n    background: url(../img/selector-icons.svg) 0 -32px no-repeat;\n    cursor: default;\n}\n\n.stacked .active.selector-add {\n    background-position: 0 -48px;\n    cursor: pointer;\n}\n\n.stacked .selector-remove {\n    background: url(../img/selector-icons.svg) 0 0 no-repeat;\n    cursor: default;\n}\n\n.stacked .active.selector-remove {\n    background-position: 0 -16px;\n    cursor: pointer;\n}\n\n.selector .help-icon {\n    background: url(../img/icon-unknown.svg) 0 0 no-repeat;\n    display: inline-block;\n    vertical-align: middle;\n    margin: -2px 0 0 2px;\n    width: 13px;\n    height: 13px;\n}\n\n.selector .selector-chosen .help-icon {\n    background: url(../img/icon-unknown-alt.svg) 0 0 no-repeat;\n}\n\n.selector .search-label-icon {\n    background: url(../img/search.svg) 0 0 no-repeat;\n    display: inline-block;\n    height: 18px;\n    width: 18px;\n}\n\n/* DATE AND TIME */\n\np.datetime {\n    line-height: 20px;\n    margin: 0;\n    padding: 0;\n    color: #666;\n    font-weight: bold;\n}\n\n.datetime span {\n    white-space: nowrap;\n    font-weight: normal;\n    font-size: 11px;\n    color: #ccc;\n}\n\n.datetime input, .form-row .datetime input.vDateField, .form-row .datetime input.vTimeField {\n    min-width: 0;\n    margin-left: 5px;\n    margin-bottom: 4px;\n}\n\ntable p.datetime {\n    font-size: 11px;\n    margin-left: 0;\n    padding-left: 0;\n}\n\n.datetimeshortcuts .clock-icon, .datetimeshortcuts .date-icon {\n    position: relative;\n    display: inline-block;\n    vertical-align: middle;\n    height: 16px;\n    width: 16px;\n    overflow: hidden;\n}\n\n.datetimeshortcuts .clock-icon {\n    background: url(../img/icon-clock.svg) 0 0 no-repeat;\n}\n\n.datetimeshortcuts a:focus .clock-icon,\n.datetimeshortcuts a:hover .clock-icon {\n    background-position: 0 -16px;\n}\n\n.datetimeshortcuts .date-icon {\n    background: url(../img/icon-calendar.svg) 0 0 no-repeat;\n    top: -1px;\n}\n\n.datetimeshortcuts a:focus .date-icon,\n.datetimeshortcuts a:hover .date-icon {\n    background-position: 0 -16px;\n}\n\n.timezonewarning {\n    font-size: 11px;\n    color: #999;\n}\n\n/* URL */\n\np.url {\n    line-height: 20px;\n    margin: 0;\n    padding: 0;\n    color: #666;\n    font-size: 11px;\n    font-weight: bold;\n}\n\n.url a {\n    font-weight: normal;\n}\n\n/* FILE UPLOADS */\n\np.file-upload {\n    line-height: 20px;\n    margin: 0;\n    padding: 0;\n    color: #666;\n    font-size: 11px;\n    font-weight: bold;\n}\n\n.aligned p.file-upload {\n    margin-left: 170px;\n}\n\n.file-upload a {\n    font-weight: normal;\n}\n\n.file-upload .deletelink {\n    margin-left: 5px;\n}\n\nspan.clearable-file-input label {\n    color: #333;\n    font-size: 11px;\n    display: inline;\n    float: none;\n}\n\n/* CALENDARS & CLOCKS */\n\n.calendarbox, .clockbox {\n    margin: 5px auto;\n    font-size: 12px;\n    width: 19em;\n    text-align: center;\n    background: white;\n    border: 1px solid #ddd;\n    border-radius: 4px;\n    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);\n    overflow: hidden;\n    position: relative;\n}\n\n.clockbox {\n    width: auto;\n}\n\n.calendar {\n    margin: 0;\n    padding: 0;\n}\n\n.calendar table {\n    margin: 0;\n    padding: 0;\n    border-collapse: collapse;\n    background: white;\n    width: 100%;\n}\n\n.calendar caption, .calendarbox h2 {\n    margin: 0;\n    text-align: center;\n    border-top: none;\n    background: #f5dd5d;\n    font-weight: 700;\n    font-size: 12px;\n    color: #333;\n}\n\n.calendar th {\n    padding: 8px 5px;\n    background: #f8f8f8;\n    border-bottom: 1px solid #ddd;\n    font-weight: 400;\n    font-size: 12px;\n    text-align: center;\n    color: #666;\n}\n\n.calendar td {\n    font-weight: 400;\n    font-size: 12px;\n    text-align: center;\n    padding: 0;\n    border-top: 1px solid #eee;\n    border-bottom: none;\n}\n\n.calendar td.selected a {\n    background: #79aec8;\n    color: #fff;\n}\n\n.calendar td.nonday {\n    background: #f8f8f8;\n}\n\n.calendar td.today a {\n    font-weight: 700;\n}\n\n.calendar td a, .timelist a {\n    display: block;\n    font-weight: 400;\n    padding: 6px;\n    text-decoration: none;\n    color: #444;\n}\n\n.calendar td a:focus, .timelist a:focus,\n.calendar td a:hover, .timelist a:hover {\n    background: #79aec8;\n    color: white;\n}\n\n.calendar td a:active, .timelist a:active {\n    background: #417690;\n    color: white;\n}\n\n.calendarnav {\n    font-size: 10px;\n    text-align: center;\n    color: #ccc;\n    margin: 0;\n    padding: 1px 3px;\n}\n\n.calendarnav a:link, #calendarnav a:visited,\n#calendarnav a:focus, #calendarnav a:hover {\n    color: #999;\n}\n\n.calendar-shortcuts {\n    background: white;\n    font-size: 11px;\n    line-height: 11px;\n    border-top: 1px solid #eee;\n    padding: 8px 0;\n    color: #ccc;\n}\n\n.calendarbox .calendarnav-previous, .calendarbox .calendarnav-next {\n    display: block;\n    position: absolute;\n    top: 8px;\n    width: 15px;\n    height: 15px;\n    text-indent: -9999px;\n    padding: 0;\n}\n\n.calendarnav-previous {\n    left: 10px;\n    background: url(../img/calendar-icons.svg) 0 0 no-repeat;\n}\n\n.calendarbox .calendarnav-previous:focus,\n.calendarbox .calendarnav-previous:hover {\n    background-position: 0 -15px;\n}\n\n.calendarnav-next {\n    right: 10px;\n    background: url(../img/calendar-icons.svg) 0 -30px no-repeat;\n}\n\n.calendarbox .calendarnav-next:focus,\n.calendarbox .calendarnav-next:hover {\n    background-position: 0 -45px;\n}\n\n.calendar-cancel {\n    margin: 0;\n    padding: 4px 0;\n    font-size: 12px;\n    background: #eee;\n    border-top: 1px solid #ddd;\n    color: #333;\n}\n\n.calendar-cancel:focus, .calendar-cancel:hover {\n    background: #ddd;\n}\n\n.calendar-cancel a {\n    color: black;\n    display: block;\n}\n\nul.timelist, .timelist li {\n    list-style-type: none;\n    margin: 0;\n    padding: 0;\n}\n\n.timelist a {\n    padding: 2px;\n}\n\n/* EDIT INLINE */\n\n.inline-deletelink {\n    float: right;\n    text-indent: -9999px;\n    background: url(../img/inline-delete.svg) 0 0 no-repeat;\n    width: 16px;\n    height: 16px;\n    border: 0px none;\n}\n\n.inline-deletelink:focus, .inline-deletelink:hover {\n    cursor: pointer;\n}\n\n/* RELATED WIDGET WRAPPER */\n.related-widget-wrapper {\n    float: left;       /* display properly in form rows with multiple fields */\n    overflow: hidden;  /* clear floated contents */\n}\n\n.related-widget-wrapper-link {\n    opacity: 0.3;\n}\n\n.related-widget-wrapper-link:link {\n    opacity: .8;\n}\n\n.related-widget-wrapper-link:link:focus,\n.related-widget-wrapper-link:link:hover {\n    opacity: 1;\n}\n\nselect + .related-widget-wrapper-link,\n.related-widget-wrapper-link + .related-widget-wrapper-link {\n    margin-left: 7px;\n}\n"
  },
  {
    "path": "static_cdn/static_root/admin/fonts/LICENSE.txt",
    "content": "\r\n                                 Apache License\r\n                           Version 2.0, January 2004\r\n                        http://www.apache.org/licenses/\r\n\r\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r\n\r\n   1. Definitions.\r\n\r\n      \"License\" shall mean the terms and conditions for use, reproduction,\r\n      and distribution as defined by Sections 1 through 9 of this document.\r\n\r\n      \"Licensor\" shall mean the copyright owner or entity authorized by\r\n      the copyright owner that is granting the License.\r\n\r\n      \"Legal Entity\" shall mean the union of the acting entity and all\r\n      other entities that control, are controlled by, or are under common\r\n      control with that entity. For the purposes of this definition,\r\n      \"control\" means (i) the power, direct or indirect, to cause the\r\n      direction or management of such entity, whether by contract or\r\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\r\n      outstanding shares, or (iii) beneficial ownership of such entity.\r\n\r\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\r\n      exercising permissions granted by this License.\r\n\r\n      \"Source\" form shall mean the preferred form for making modifications,\r\n      including but not limited to software source code, documentation\r\n      source, and configuration files.\r\n\r\n      \"Object\" form shall mean any form resulting from mechanical\r\n      transformation or translation of a Source form, including but\r\n      not limited to compiled object code, generated documentation,\r\n      and conversions to other media types.\r\n\r\n      \"Work\" shall mean the work of authorship, whether in Source or\r\n      Object form, made available under the License, as indicated by a\r\n      copyright notice that is included in or attached to the work\r\n      (an example is provided in the Appendix below).\r\n\r\n      \"Derivative Works\" shall mean any work, whether in Source or Object\r\n      form, that is based on (or derived from) the Work and for which the\r\n      editorial revisions, annotations, elaborations, or other modifications\r\n      represent, as a whole, an original work of authorship. For the purposes\r\n      of this License, Derivative Works shall not include works that remain\r\n      separable from, or merely link (or bind by name) to the interfaces of,\r\n      the Work and Derivative Works thereof.\r\n\r\n      \"Contribution\" shall mean any work of authorship, including\r\n      the original version of the Work and any modifications or additions\r\n      to that Work or Derivative Works thereof, that is intentionally\r\n      submitted to Licensor for inclusion in the Work by the copyright owner\r\n      or by an individual or Legal Entity authorized to submit on behalf of\r\n      the copyright owner. For the purposes of this definition, \"submitted\"\r\n      means any form of electronic, verbal, or written communication sent\r\n      to the Licensor or its representatives, including but not limited to\r\n      communication on electronic mailing lists, source code control systems,\r\n      and issue tracking systems that are managed by, or on behalf of, the\r\n      Licensor for the purpose of discussing and improving the Work, but\r\n      excluding communication that is conspicuously marked or otherwise\r\n      designated in writing by the copyright owner as \"Not a Contribution.\"\r\n\r\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\r\n      on behalf of whom a Contribution has been received by Licensor and\r\n      subsequently incorporated within the Work.\r\n\r\n   2. Grant of Copyright License. Subject to the terms and conditions of\r\n      this License, each Contributor hereby grants to You a perpetual,\r\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r\n      copyright license to reproduce, prepare Derivative Works of,\r\n      publicly display, publicly perform, sublicense, and distribute the\r\n      Work and such Derivative Works in Source or Object form.\r\n\r\n   3. Grant of Patent License. Subject to the terms and conditions of\r\n      this License, each Contributor hereby grants to You a perpetual,\r\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r\n      (except as stated in this section) patent license to make, have made,\r\n      use, offer to sell, sell, import, and otherwise transfer the Work,\r\n      where such license applies only to those patent claims licensable\r\n      by such Contributor that are necessarily infringed by their\r\n      Contribution(s) alone or by combination of their Contribution(s)\r\n      with the Work to which such Contribution(s) was submitted. If You\r\n      institute patent litigation against any entity (including a\r\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\r\n      or a Contribution incorporated within the Work constitutes direct\r\n      or contributory patent infringement, then any patent licenses\r\n      granted to You under this License for that Work shall terminate\r\n      as of the date such litigation is filed.\r\n\r\n   4. Redistribution. You may reproduce and distribute copies of the\r\n      Work or Derivative Works thereof in any medium, with or without\r\n      modifications, and in Source or Object form, provided that You\r\n      meet the following conditions:\r\n\r\n      (a) You must give any other recipients of the Work or\r\n          Derivative Works a copy of this License; and\r\n\r\n      (b) You must cause any modified files to carry prominent notices\r\n          stating that You changed the files; and\r\n\r\n      (c) You must retain, in the Source form of any Derivative Works\r\n          that You distribute, all copyright, patent, trademark, and\r\n          attribution notices from the Source form of the Work,\r\n          excluding those notices that do not pertain to any part of\r\n          the Derivative Works; and\r\n\r\n      (d) If the Work includes a \"NOTICE\" text file as part of its\r\n          distribution, then any Derivative Works that You distribute must\r\n          include a readable copy of the attribution notices contained\r\n          within such NOTICE file, excluding those notices that do not\r\n          pertain to any part of the Derivative Works, in at least one\r\n          of the following places: within a NOTICE text file distributed\r\n          as part of the Derivative Works; within the Source form or\r\n          documentation, if provided along with the Derivative Works; or,\r\n          within a display generated by the Derivative Works, if and\r\n          wherever such third-party notices normally appear. The contents\r\n          of the NOTICE file are for informational purposes only and\r\n          do not modify the License. You may add Your own attribution\r\n          notices within Derivative Works that You distribute, alongside\r\n          or as an addendum to the NOTICE text from the Work, provided\r\n          that such additional attribution notices cannot be construed\r\n          as modifying the License.\r\n\r\n      You may add Your own copyright statement to Your modifications and\r\n      may provide additional or different license terms and conditions\r\n      for use, reproduction, or distribution of Your modifications, or\r\n      for any such Derivative Works as a whole, provided Your use,\r\n      reproduction, and distribution of the Work otherwise complies with\r\n      the conditions stated in this License.\r\n\r\n   5. Submission of Contributions. Unless You explicitly state otherwise,\r\n      any Contribution intentionally submitted for inclusion in the Work\r\n      by You to the Licensor shall be under the terms and conditions of\r\n      this License, without any additional terms or conditions.\r\n      Notwithstanding the above, nothing herein shall supersede or modify\r\n      the terms of any separate license agreement you may have executed\r\n      with Licensor regarding such Contributions.\r\n\r\n   6. Trademarks. This License does not grant permission to use the trade\r\n      names, trademarks, service marks, or product names of the Licensor,\r\n      except as required for reasonable and customary use in describing the\r\n      origin of the Work and reproducing the content of the NOTICE file.\r\n\r\n   7. Disclaimer of Warranty. Unless required by applicable law or\r\n      agreed to in writing, Licensor provides the Work (and each\r\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\r\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\r\n      implied, including, without limitation, any warranties or conditions\r\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\r\n      PARTICULAR PURPOSE. You are solely responsible for determining the\r\n      appropriateness of using or redistributing the Work and assume any\r\n      risks associated with Your exercise of permissions under this License.\r\n\r\n   8. Limitation of Liability. In no event and under no legal theory,\r\n      whether in tort (including negligence), contract, or otherwise,\r\n      unless required by applicable law (such as deliberate and grossly\r\n      negligent acts) or agreed to in writing, shall any Contributor be\r\n      liable to You for damages, including any direct, indirect, special,\r\n      incidental, or consequential damages of any character arising as a\r\n      result of this License or out of the use or inability to use the\r\n      Work (including but not limited to damages for loss of goodwill,\r\n      work stoppage, computer failure or malfunction, or any and all\r\n      other commercial damages or losses), even if such Contributor\r\n      has been advised of the possibility of such damages.\r\n\r\n   9. Accepting Warranty or Additional Liability. While redistributing\r\n      the Work or Derivative Works thereof, You may choose to offer,\r\n      and charge a fee for, acceptance of support, warranty, indemnity,\r\n      or other liability obligations and/or rights consistent with this\r\n      License. However, in accepting such obligations, You may act only\r\n      on Your own behalf and on Your sole responsibility, not on behalf\r\n      of any other Contributor, and only if You agree to indemnify,\r\n      defend, and hold each Contributor harmless for any liability\r\n      incurred by, or claims asserted against, such Contributor by reason\r\n      of your accepting any such warranty or additional liability.\r\n\r\n   END OF TERMS AND CONDITIONS\r\n\r\n   APPENDIX: How to apply the Apache License to your work.\r\n\r\n      To apply the Apache License to your work, attach the following\r\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\r\n      replaced with your own identifying information. (Don't include\r\n      the brackets!)  The text should be enclosed in the appropriate\r\n      comment syntax for the file format. We also recommend that a\r\n      file or class name and description of purpose be included on the\r\n      same \"printed page\" as the copyright notice for easier\r\n      identification within third-party archives.\r\n\r\n   Copyright [yyyy] [name of copyright owner]\r\n\r\n   Licensed under the Apache License, Version 2.0 (the \"License\");\r\n   you may not use this file except in compliance with the License.\r\n   You may obtain a copy of the License at\r\n\r\n       http://www.apache.org/licenses/LICENSE-2.0\r\n\r\n   Unless required by applicable law or agreed to in writing, software\r\n   distributed under the License is distributed on an \"AS IS\" BASIS,\r\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n   See the License for the specific language governing permissions and\r\n   limitations under the License.\r\n"
  },
  {
    "path": "static_cdn/static_root/admin/fonts/README.txt",
    "content": "Roboto webfont source: https://www.google.com/fonts/specimen/Roboto\nWeights used in this project: Light (300), Regular (400), Bold (700)\n"
  },
  {
    "path": "static_cdn/static_root/admin/img/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014 Code Charm Ltd\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "static_cdn/static_root/admin/img/README.txt",
    "content": "All icons are taken from Font Awesome (http://fontawesome.io/) project.\nThe Font Awesome font is licensed under the SIL OFL 1.1:\n- http://scripts.sil.org/OFL\n\nSVG icons source: https://github.com/encharm/Font-Awesome-SVG-PNG\nFont-Awesome-SVG-PNG is licensed under the MIT license (see file license\nin current folder).\n"
  },
  {
    "path": "static_cdn/static_root/admin/js/SelectBox.js",
    "content": "(function($) {\n    'use strict';\n    var SelectBox = {\n        cache: {},\n        init: function(id) {\n            var box = document.getElementById(id);\n            var node;\n            SelectBox.cache[id] = [];\n            var cache = SelectBox.cache[id];\n            var boxOptions = box.options;\n            var boxOptionsLength = boxOptions.length;\n            for (var i = 0, j = boxOptionsLength; i < j; i++) {\n                node = boxOptions[i];\n                cache.push({value: node.value, text: node.text, displayed: 1});\n            }\n        },\n        redisplay: function(id) {\n            // Repopulate HTML select box from cache\n            var box = document.getElementById(id);\n            var node;\n            $(box).empty(); // clear all options\n            var new_options = box.outerHTML.slice(0, -9);  // grab just the opening tag\n            var cache = SelectBox.cache[id];\n            for (var i = 0, j = cache.length; i < j; i++) {\n                node = cache[i];\n                if (node.displayed) {\n                    var new_option = new Option(node.text, node.value, false, false);\n                    // Shows a tooltip when hovering over the option\n                    new_option.setAttribute(\"title\", node.text);\n                    new_options += new_option.outerHTML;\n                }\n            }\n            new_options += '</select>';\n            box.outerHTML = new_options;\n        },\n        filter: function(id, text) {\n            // Redisplay the HTML select box, displaying only the choices containing ALL\n            // the words in text. (It's an AND search.)\n            var tokens = text.toLowerCase().split(/\\s+/);\n            var node, token;\n            var cache = SelectBox.cache[id];\n            for (var i = 0, j = cache.length; i < j; i++) {\n                node = cache[i];\n                node.displayed = 1;\n                var node_text = node.text.toLowerCase();\n                var numTokens = tokens.length;\n                for (var k = 0; k < numTokens; k++) {\n                    token = tokens[k];\n                    if (node_text.indexOf(token) === -1) {\n                        node.displayed = 0;\n                        break;  // Once the first token isn't found we're done\n                    }\n                }\n            }\n            SelectBox.redisplay(id);\n        },\n        delete_from_cache: function(id, value) {\n            var node, delete_index = null;\n            var cache = SelectBox.cache[id];\n            for (var i = 0, j = cache.length; i < j; i++) {\n                node = cache[i];\n                if (node.value === value) {\n                    delete_index = i;\n                    break;\n                }\n            }\n            cache.splice(delete_index, 1);\n        },\n        add_to_cache: function(id, option) {\n            SelectBox.cache[id].push({value: option.value, text: option.text, displayed: 1});\n        },\n        cache_contains: function(id, value) {\n            // Check if an item is contained in the cache\n            var node;\n            var cache = SelectBox.cache[id];\n            for (var i = 0, j = cache.length; i < j; i++) {\n                node = cache[i];\n                if (node.value === value) {\n                    return true;\n                }\n            }\n            return false;\n        },\n        move: function(from, to) {\n            var from_box = document.getElementById(from);\n            var option;\n            var boxOptions = from_box.options;\n            var boxOptionsLength = boxOptions.length;\n            for (var i = 0, j = boxOptionsLength; i < j; i++) {\n                option = boxOptions[i];\n                var option_value = option.value;\n                if (option.selected && SelectBox.cache_contains(from, option_value)) {\n                    SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1});\n                    SelectBox.delete_from_cache(from, option_value);\n                }\n            }\n            SelectBox.redisplay(from);\n            SelectBox.redisplay(to);\n        },\n        move_all: function(from, to) {\n            var from_box = document.getElementById(from);\n            var option;\n            var boxOptions = from_box.options;\n            var boxOptionsLength = boxOptions.length;\n            for (var i = 0, j = boxOptionsLength; i < j; i++) {\n                option = boxOptions[i];\n                var option_value = option.value;\n                if (SelectBox.cache_contains(from, option_value)) {\n                    SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1});\n                    SelectBox.delete_from_cache(from, option_value);\n                }\n            }\n            SelectBox.redisplay(from);\n            SelectBox.redisplay(to);\n        },\n        sort: function(id) {\n            SelectBox.cache[id].sort(function(a, b) {\n                a = a.text.toLowerCase();\n                b = b.text.toLowerCase();\n                try {\n                    if (a > b) {\n                        return 1;\n                    }\n                    if (a < b) {\n                        return -1;\n                    }\n                }\n                catch (e) {\n                    // silently fail on IE 'unknown' exception\n                }\n                return 0;\n            } );\n        },\n        select_all: function(id) {\n            var box = document.getElementById(id);\n            var boxOptions = box.options;\n            var boxOptionsLength = boxOptions.length;\n            for (var i = 0; i < boxOptionsLength; i++) {\n                boxOptions[i].selected = 'selected';\n            }\n        }\n    };\n    window.SelectBox = SelectBox;\n})(django.jQuery);\n"
  },
  {
    "path": "static_cdn/static_root/admin/js/SelectFilter2.js",
    "content": "/*global SelectBox, addEvent, gettext, interpolate, quickElement, SelectFilter*/\n/*\nSelectFilter2 - Turns a multiple-select box into a filter interface.\n\nRequires jQuery, core.js, and SelectBox.js.\n*/\n(function($) {\n    'use strict';\n    function findForm(node) {\n        // returns the node of the form containing the given node\n        if (node.tagName.toLowerCase() !== 'form') {\n            return findForm(node.parentNode);\n        }\n        return node;\n    }\n\n    window.SelectFilter = {\n        init: function(field_id, field_name, is_stacked) {\n            if (field_id.match(/__prefix__/)) {\n                // Don't initialize on empty forms.\n                return;\n            }\n            var from_box = document.getElementById(field_id);\n            from_box.id += '_from'; // change its ID\n            from_box.className = 'filtered';\n\n            var ps = from_box.parentNode.getElementsByTagName('p');\n            for (var i = 0; i < ps.length; i++) {\n                if (ps[i].className.indexOf(\"info\") !== -1) {\n                    // Remove <p class=\"info\">, because it just gets in the way.\n                    from_box.parentNode.removeChild(ps[i]);\n                } else if (ps[i].className.indexOf(\"help\") !== -1) {\n                    // Move help text up to the top so it isn't below the select\n                    // boxes or wrapped off on the side to the right of the add\n                    // button:\n                    from_box.parentNode.insertBefore(ps[i], from_box.parentNode.firstChild);\n                }\n            }\n\n            // <div class=\"selector\"> or <div class=\"selector stacked\">\n            var selector_div = quickElement('div', from_box.parentNode);\n            selector_div.className = is_stacked ? 'selector stacked' : 'selector';\n\n            // <div class=\"selector-available\">\n            var selector_available = quickElement('div', selector_div);\n            selector_available.className = 'selector-available';\n            var title_available = quickElement('h2', selector_available, interpolate(gettext('Available %s') + ' ', [field_name]));\n            quickElement(\n                'span', title_available, '',\n                'class', 'help help-tooltip help-icon',\n                'title', interpolate(\n                    gettext(\n                        'This is the list of available %s. You may choose some by ' +\n                        'selecting them in the box below and then clicking the ' +\n                        '\"Choose\" arrow between the two boxes.'\n                    ),\n                    [field_name]\n                )\n            );\n\n            var filter_p = quickElement('p', selector_available, '', 'id', field_id + '_filter');\n            filter_p.className = 'selector-filter';\n\n            var search_filter_label = quickElement('label', filter_p, '', 'for', field_id + '_input');\n\n            quickElement(\n                'span', search_filter_label, '',\n                'class', 'help-tooltip search-label-icon',\n                'title', interpolate(gettext(\"Type into this box to filter down the list of available %s.\"), [field_name])\n            );\n\n            filter_p.appendChild(document.createTextNode(' '));\n\n            var filter_input = quickElement('input', filter_p, '', 'type', 'text', 'placeholder', gettext(\"Filter\"));\n            filter_input.id = field_id + '_input';\n\n            selector_available.appendChild(from_box);\n            var choose_all = quickElement('a', selector_available, gettext('Choose all'), 'title', interpolate(gettext('Click to choose all %s at once.'), [field_name]), 'href', '#', 'id', field_id + '_add_all_link');\n            choose_all.className = 'selector-chooseall';\n\n            // <ul class=\"selector-chooser\">\n            var selector_chooser = quickElement('ul', selector_div);\n            selector_chooser.className = 'selector-chooser';\n            var add_link = quickElement('a', quickElement('li', selector_chooser), gettext('Choose'), 'title', gettext('Choose'), 'href', '#', 'id', field_id + '_add_link');\n            add_link.className = 'selector-add';\n            var remove_link = quickElement('a', quickElement('li', selector_chooser), gettext('Remove'), 'title', gettext('Remove'), 'href', '#', 'id', field_id + '_remove_link');\n            remove_link.className = 'selector-remove';\n\n            // <div class=\"selector-chosen\">\n            var selector_chosen = quickElement('div', selector_div);\n            selector_chosen.className = 'selector-chosen';\n            var title_chosen = quickElement('h2', selector_chosen, interpolate(gettext('Chosen %s') + ' ', [field_name]));\n            quickElement(\n                'span', title_chosen, '',\n                'class', 'help help-tooltip help-icon',\n                'title', interpolate(\n                    gettext(\n                        'This is the list of chosen %s. You may remove some by ' +\n                        'selecting them in the box below and then clicking the ' +\n                        '\"Remove\" arrow between the two boxes.'\n                    ),\n                    [field_name]\n                )\n            );\n\n            var to_box = quickElement('select', selector_chosen, '', 'id', field_id + '_to', 'multiple', 'multiple', 'size', from_box.size, 'name', from_box.getAttribute('name'));\n            to_box.className = 'filtered';\n            var clear_all = quickElement('a', selector_chosen, gettext('Remove all'), 'title', interpolate(gettext('Click to remove all chosen %s at once.'), [field_name]), 'href', '#', 'id', field_id + '_remove_all_link');\n            clear_all.className = 'selector-clearall';\n\n            from_box.setAttribute('name', from_box.getAttribute('name') + '_old');\n\n            // Set up the JavaScript event handlers for the select box filter interface\n            var move_selection = function(e, elem, move_func, from, to) {\n                if (elem.className.indexOf('active') !== -1) {\n                    move_func(from, to);\n                    SelectFilter.refresh_icons(field_id);\n                }\n                e.preventDefault();\n            };\n            addEvent(choose_all, 'click', function(e) { move_selection(e, this, SelectBox.move_all, field_id + '_from', field_id + '_to'); });\n            addEvent(add_link, 'click', function(e) { move_selection(e, this, SelectBox.move, field_id + '_from', field_id + '_to'); });\n            addEvent(remove_link, 'click', function(e) { move_selection(e, this, SelectBox.move, field_id + '_to', field_id + '_from'); });\n            addEvent(clear_all, 'click', function(e) { move_selection(e, this, SelectBox.move_all, field_id + '_to', field_id + '_from'); });\n            addEvent(filter_input, 'keypress', function(e) { SelectFilter.filter_key_press(e, field_id); });\n            addEvent(filter_input, 'keyup', function(e) { SelectFilter.filter_key_up(e, field_id); });\n            addEvent(filter_input, 'keydown', function(e) { SelectFilter.filter_key_down(e, field_id); });\n            addEvent(selector_div, 'change', function(e) {\n                if (e.target.tagName === 'SELECT') {\n                    SelectFilter.refresh_icons(field_id);\n                }\n            });\n            addEvent(selector_div, 'dblclick', function(e) {\n                if (e.target.tagName === 'OPTION') {\n                    if (e.target.closest('select').id === field_id + '_to') {\n                        SelectBox.move(field_id + '_to', field_id + '_from');\n                    } else {\n                        SelectBox.move(field_id + '_from', field_id + '_to');\n                    }\n                    SelectFilter.refresh_icons(field_id);\n                }\n            });\n            addEvent(findForm(from_box), 'submit', function() { SelectBox.select_all(field_id + '_to'); });\n            SelectBox.init(field_id + '_from');\n            SelectBox.init(field_id + '_to');\n            // Move selected from_box options to to_box\n            SelectBox.move(field_id + '_from', field_id + '_to');\n\n            if (!is_stacked) {\n                // In horizontal mode, give the same height to the two boxes.\n                var j_from_box = $(from_box);\n                var j_to_box = $(to_box);\n                var resize_filters = function() { j_to_box.height($(filter_p).outerHeight() + j_from_box.outerHeight()); };\n                if (j_from_box.outerHeight() > 0) {\n                    resize_filters(); // This fieldset is already open. Resize now.\n                } else {\n                    // This fieldset is probably collapsed. Wait for its 'show' event.\n                    j_to_box.closest('fieldset').one('show.fieldset', resize_filters);\n                }\n            }\n\n            // Initial icon refresh\n            SelectFilter.refresh_icons(field_id);\n        },\n        any_selected: function(field) {\n            var any_selected = false;\n            try {\n                // Temporarily add the required attribute and check validity.\n                // This is much faster in WebKit browsers than the fallback.\n                field.attr('required', 'required');\n                any_selected = field.is(':valid');\n                field.removeAttr('required');\n            } catch (e) {\n                // Browsers that don't support :valid (IE < 10)\n                any_selected = field.find('option:selected').length > 0;\n            }\n            return any_selected;\n        },\n        refresh_icons: function(field_id) {\n            var from = $('#' + field_id + '_from');\n            var to = $('#' + field_id + '_to');\n            // Active if at least one item is selected\n            $('#' + field_id + '_add_link').toggleClass('active', SelectFilter.any_selected(from));\n            $('#' + field_id + '_remove_link').toggleClass('active', SelectFilter.any_selected(to));\n            // Active if the corresponding box isn't empty\n            $('#' + field_id + '_add_all_link').toggleClass('active', from.find('option').length > 0);\n            $('#' + field_id + '_remove_all_link').toggleClass('active', to.find('option').length > 0);\n        },\n        filter_key_press: function(event, field_id) {\n            var from = document.getElementById(field_id + '_from');\n            // don't submit form if user pressed Enter\n            if ((event.which && event.which === 13) || (event.keyCode && event.keyCode === 13)) {\n                from.selectedIndex = 0;\n                SelectBox.move(field_id + '_from', field_id + '_to');\n                from.selectedIndex = 0;\n                event.preventDefault();\n                return false;\n            }\n        },\n        filter_key_up: function(event, field_id) {\n            var from = document.getElementById(field_id + '_from');\n            var temp = from.selectedIndex;\n            SelectBox.filter(field_id + '_from', document.getElementById(field_id + '_input').value);\n            from.selectedIndex = temp;\n            return true;\n        },\n        filter_key_down: function(event, field_id) {\n            var from = document.getElementById(field_id + '_from');\n            // right arrow -- move across\n            if ((event.which && event.which === 39) || (event.keyCode && event.keyCode === 39)) {\n                var old_index = from.selectedIndex;\n                SelectBox.move(field_id + '_from', field_id + '_to');\n                from.selectedIndex = (old_index === from.length) ? from.length - 1 : old_index;\n                return false;\n            }\n            // down arrow -- wrap around\n            if ((event.which && event.which === 40) || (event.keyCode && event.keyCode === 40)) {\n                from.selectedIndex = (from.length === from.selectedIndex + 1) ? 0 : from.selectedIndex + 1;\n            }\n            // up arrow -- wrap around\n            if ((event.which && event.which === 38) || (event.keyCode && event.keyCode === 38)) {\n                from.selectedIndex = (from.selectedIndex === 0) ? from.length - 1 : from.selectedIndex - 1;\n            }\n            return true;\n        }\n    };\n\n    addEvent(window, 'load', function(e) {\n        $('select.selectfilter, select.selectfilterstacked').each(function() {\n            var $el = $(this),\n                data = $el.data();\n            SelectFilter.init($el.attr('id'), data.fieldName, parseInt(data.isStacked, 10));\n        });\n    });\n\n})(django.jQuery);\n"
  },
  {
    "path": "static_cdn/static_root/admin/js/actions.js",
    "content": "/*global gettext, interpolate, ngettext*/\n(function($) {\n    'use strict';\n    var lastChecked;\n\n    $.fn.actions = function(opts) {\n        var options = $.extend({}, $.fn.actions.defaults, opts);\n        var actionCheckboxes = $(this);\n        var list_editable_changed = false;\n        var showQuestion = function() {\n            $(options.acrossClears).hide();\n            $(options.acrossQuestions).show();\n            $(options.allContainer).hide();\n        },\n        showClear = function() {\n            $(options.acrossClears).show();\n            $(options.acrossQuestions).hide();\n            $(options.actionContainer).toggleClass(options.selectedClass);\n            $(options.allContainer).show();\n            $(options.counterContainer).hide();\n        },\n        reset = function() {\n            $(options.acrossClears).hide();\n            $(options.acrossQuestions).hide();\n            $(options.allContainer).hide();\n            $(options.counterContainer).show();\n        },\n        clearAcross = function() {\n            reset();\n            $(options.acrossInput).val(0);\n            $(options.actionContainer).removeClass(options.selectedClass);\n        },\n        checker = function(checked) {\n            if (checked) {\n                showQuestion();\n            } else {\n                reset();\n            }\n            $(actionCheckboxes).prop(\"checked\", checked)\n                .parent().parent().toggleClass(options.selectedClass, checked);\n        },\n        updateCounter = function() {\n            var sel = $(actionCheckboxes).filter(\":checked\").length;\n            // data-actions-icnt is defined in the generated HTML\n            // and contains the total amount of objects in the queryset\n            var actions_icnt = $('.action-counter').data('actionsIcnt');\n            $(options.counterContainer).html(interpolate(\n            ngettext('%(sel)s of %(cnt)s selected', '%(sel)s of %(cnt)s selected', sel), {\n                sel: sel,\n                cnt: actions_icnt\n            }, true));\n            $(options.allToggle).prop(\"checked\", function() {\n                var value;\n                if (sel === actionCheckboxes.length) {\n                    value = true;\n                    showQuestion();\n                } else {\n                    value = false;\n                    clearAcross();\n                }\n                return value;\n            });\n        };\n        // Show counter by default\n        $(options.counterContainer).show();\n        // Check state of checkboxes and reinit state if needed\n        $(this).filter(\":checked\").each(function(i) {\n            $(this).parent().parent().toggleClass(options.selectedClass);\n            updateCounter();\n            if ($(options.acrossInput).val() === 1) {\n                showClear();\n            }\n        });\n        $(options.allToggle).show().click(function() {\n            checker($(this).prop(\"checked\"));\n            updateCounter();\n        });\n        $(\"a\", options.acrossQuestions).click(function(event) {\n            event.preventDefault();\n            $(options.acrossInput).val(1);\n            showClear();\n        });\n        $(\"a\", options.acrossClears).click(function(event) {\n            event.preventDefault();\n            $(options.allToggle).prop(\"checked\", false);\n            clearAcross();\n            checker(0);\n            updateCounter();\n        });\n        lastChecked = null;\n        $(actionCheckboxes).click(function(event) {\n            if (!event) { event = window.event; }\n            var target = event.target ? event.target : event.srcElement;\n            if (lastChecked && $.data(lastChecked) !== $.data(target) && event.shiftKey === true) {\n                var inrange = false;\n                $(lastChecked).prop(\"checked\", target.checked)\n                    .parent().parent().toggleClass(options.selectedClass, target.checked);\n                $(actionCheckboxes).each(function() {\n                    if ($.data(this) === $.data(lastChecked) || $.data(this) === $.data(target)) {\n                        inrange = (inrange) ? false : true;\n                    }\n                    if (inrange) {\n                        $(this).prop(\"checked\", target.checked)\n                            .parent().parent().toggleClass(options.selectedClass, target.checked);\n                    }\n                });\n            }\n            $(target).parent().parent().toggleClass(options.selectedClass, target.checked);\n            lastChecked = target;\n            updateCounter();\n        });\n        $('form#changelist-form table#result_list tr').find('td:gt(0) :input').change(function() {\n            list_editable_changed = true;\n        });\n        $('form#changelist-form button[name=\"index\"]').click(function(event) {\n            if (list_editable_changed) {\n                return confirm(gettext(\"You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost.\"));\n            }\n        });\n        $('form#changelist-form input[name=\"_save\"]').click(function(event) {\n            var action_changed = false;\n            $('select option:selected', options.actionContainer).each(function() {\n                if ($(this).val()) {\n                    action_changed = true;\n                }\n            });\n            if (action_changed) {\n                if (list_editable_changed) {\n                    return confirm(gettext(\"You have selected an action, but you haven't saved your changes to individual fields yet. Please click OK to save. You'll need to re-run the action.\"));\n                } else {\n                    return confirm(gettext(\"You have selected an action, and you haven't made any changes on individual fields. You're probably looking for the Go button rather than the Save button.\"));\n                }\n            }\n        });\n    };\n    /* Setup plugin defaults */\n    $.fn.actions.defaults = {\n        actionContainer: \"div.actions\",\n        counterContainer: \"span.action-counter\",\n        allContainer: \"div.actions span.all\",\n        acrossInput: \"div.actions input.select-across\",\n        acrossQuestions: \"div.actions span.question\",\n        acrossClears: \"div.actions span.clear\",\n        allToggle: \"#action-toggle\",\n        selectedClass: \"selected\"\n    };\n    $(document).ready(function() {\n        var $actionsEls = $('tr input.action-select');\n        if ($actionsEls.length > 0) {\n            $actionsEls.actions();\n        }\n    });\n})(django.jQuery);\n"
  },
  {
    "path": "static_cdn/static_root/admin/js/admin/DateTimeShortcuts.js",
    "content": "/*global addEvent, Calendar, cancelEventPropagation, findPosX, findPosY, getStyle, get_format, gettext, interpolate, ngettext, quickElement, removeEvent*/\n// Inserts shortcut buttons after all of the following:\n//     <input type=\"text\" class=\"vDateField\">\n//     <input type=\"text\" class=\"vTimeField\">\n(function() {\n    'use strict';\n    var DateTimeShortcuts = {\n        calendars: [],\n        calendarInputs: [],\n        clockInputs: [],\n        dismissClockFunc: [],\n        dismissCalendarFunc: [],\n        calendarDivName1: 'calendarbox', // name of calendar <div> that gets toggled\n        calendarDivName2: 'calendarin',  // name of <div> that contains calendar\n        calendarLinkName: 'calendarlink',// name of the link that is used to toggle\n        clockDivName: 'clockbox',        // name of clock <div> that gets toggled\n        clockLinkName: 'clocklink',      // name of the link that is used to toggle\n        shortCutsClass: 'datetimeshortcuts', // class of the clock and cal shortcuts\n        timezoneWarningClass: 'timezonewarning', // class of the warning for timezone mismatch\n        timezoneOffset: 0,\n        init: function() {\n            var body = document.getElementsByTagName('body')[0];\n            var serverOffset = body.getAttribute('data-admin-utc-offset');\n            if (serverOffset) {\n                var localOffset = new Date().getTimezoneOffset() * -60;\n                DateTimeShortcuts.timezoneOffset = localOffset - serverOffset;\n            }\n\n            var inputs = document.getElementsByTagName('input');\n            for (var i = 0; i < inputs.length; i++) {\n                var inp = inputs[i];\n                if (inp.getAttribute('type') === 'text' && inp.className.match(/vTimeField/)) {\n                    DateTimeShortcuts.addClock(inp);\n                    DateTimeShortcuts.addTimezoneWarning(inp);\n                }\n                else if (inp.getAttribute('type') === 'text' && inp.className.match(/vDateField/)) {\n                    DateTimeShortcuts.addCalendar(inp);\n                    DateTimeShortcuts.addTimezoneWarning(inp);\n                }\n            }\n        },\n        // Return the current time while accounting for the server timezone.\n        now: function() {\n            var body = document.getElementsByTagName('body')[0];\n            var serverOffset = body.getAttribute('data-admin-utc-offset');\n            if (serverOffset) {\n                var localNow = new Date();\n                var localOffset = localNow.getTimezoneOffset() * -60;\n                localNow.setTime(localNow.getTime() + 1000 * (serverOffset - localOffset));\n                return localNow;\n            } else {\n                return new Date();\n            }\n        },\n        // Add a warning when the time zone in the browser and backend do not match.\n        addTimezoneWarning: function(inp) {\n            var $ = django.jQuery;\n            var warningClass = DateTimeShortcuts.timezoneWarningClass;\n            var timezoneOffset = DateTimeShortcuts.timezoneOffset / 3600;\n\n            // Only warn if there is a time zone mismatch.\n            if (!timezoneOffset) {\n                return;\n            }\n\n            // Check if warning is already there.\n            if ($(inp).siblings('.' + warningClass).length) {\n                return;\n            }\n\n            var message;\n            if (timezoneOffset > 0) {\n                message = ngettext(\n                    'Note: You are %s hour ahead of server time.',\n                    'Note: You are %s hours ahead of server time.',\n                    timezoneOffset\n                );\n            }\n            else {\n                timezoneOffset *= -1;\n                message = ngettext(\n                    'Note: You are %s hour behind server time.',\n                    'Note: You are %s hours behind server time.',\n                    timezoneOffset\n                );\n            }\n            message = interpolate(message, [timezoneOffset]);\n\n            var $warning = $('<span>');\n            $warning.attr('class', warningClass);\n            $warning.text(message);\n\n            $(inp).parent()\n                .append($('<br>'))\n                .append($warning);\n        },\n        // Add clock widget to a given field\n        addClock: function(inp) {\n            var num = DateTimeShortcuts.clockInputs.length;\n            DateTimeShortcuts.clockInputs[num] = inp;\n            DateTimeShortcuts.dismissClockFunc[num] = function() { DateTimeShortcuts.dismissClock(num); return true; };\n\n            // Shortcut links (clock icon and \"Now\" link)\n            var shortcuts_span = document.createElement('span');\n            shortcuts_span.className = DateTimeShortcuts.shortCutsClass;\n            inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling);\n            var now_link = document.createElement('a');\n            now_link.setAttribute('href', \"#\");\n            now_link.appendChild(document.createTextNode(gettext('Now')));\n            addEvent(now_link, 'click', function(e) {\n                e.preventDefault();\n                DateTimeShortcuts.handleClockQuicklink(num, -1);\n            });\n            var clock_link = document.createElement('a');\n            clock_link.setAttribute('href', '#');\n            clock_link.id = DateTimeShortcuts.clockLinkName + num;\n            addEvent(clock_link, 'click', function(e) {\n                e.preventDefault();\n                // avoid triggering the document click handler to dismiss the clock\n                e.stopPropagation();\n                DateTimeShortcuts.openClock(num);\n            });\n\n            quickElement(\n                'span', clock_link, '',\n                'class', 'clock-icon',\n                'title', gettext('Choose a Time')\n            );\n            shortcuts_span.appendChild(document.createTextNode('\\u00A0'));\n            shortcuts_span.appendChild(now_link);\n            shortcuts_span.appendChild(document.createTextNode('\\u00A0|\\u00A0'));\n            shortcuts_span.appendChild(clock_link);\n\n            // Create clock link div\n            //\n            // Markup looks like:\n            // <div id=\"clockbox1\" class=\"clockbox module\">\n            //     <h2>Choose a time</h2>\n            //     <ul class=\"timelist\">\n            //         <li><a href=\"#\">Now</a></li>\n            //         <li><a href=\"#\">Midnight</a></li>\n            //         <li><a href=\"#\">6 a.m.</a></li>\n            //         <li><a href=\"#\">Noon</a></li>\n            //         <li><a href=\"#\">6 p.m.</a></li>\n            //     </ul>\n            //     <p class=\"calendar-cancel\"><a href=\"#\">Cancel</a></p>\n            // </div>\n\n            var clock_box = document.createElement('div');\n            clock_box.style.display = 'none';\n            clock_box.style.position = 'absolute';\n            clock_box.className = 'clockbox module';\n            clock_box.setAttribute('id', DateTimeShortcuts.clockDivName + num);\n            document.body.appendChild(clock_box);\n            addEvent(clock_box, 'click', cancelEventPropagation);\n\n            quickElement('h2', clock_box, gettext('Choose a time'));\n            var time_list = quickElement('ul', clock_box);\n            time_list.className = 'timelist';\n            var time_link = quickElement(\"a\", quickElement(\"li\", time_list), gettext(\"Now\"), \"href\", \"#\");\n            addEvent(time_link, 'click', function(e) {\n                e.preventDefault();\n                DateTimeShortcuts.handleClockQuicklink(num, -1);\n            });\n            time_link = quickElement(\"a\", quickElement(\"li\", time_list), gettext(\"Midnight\"), \"href\", \"#\");\n            addEvent(time_link, 'click', function(e) {\n                e.preventDefault();\n                DateTimeShortcuts.handleClockQuicklink(num, 0);\n            });\n            time_link = quickElement(\"a\", quickElement(\"li\", time_list), gettext(\"6 a.m.\"), \"href\", \"#\");\n            addEvent(time_link, 'click', function(e) {\n                e.preventDefault();\n                DateTimeShortcuts.handleClockQuicklink(num, 6);\n            });\n            time_link = quickElement(\"a\", quickElement(\"li\", time_list), gettext(\"Noon\"), \"href\", \"#\");\n            addEvent(time_link, 'click', function(e) {\n                e.preventDefault();\n                DateTimeShortcuts.handleClockQuicklink(num, 12);\n            });\n            time_link = quickElement(\"a\", quickElement(\"li\", time_list), gettext(\"6 p.m.\"), \"href\", \"#\");\n            addEvent(time_link, 'click', function(e) {\n                e.preventDefault();\n                DateTimeShortcuts.handleClockQuicklink(num, 18);\n            });\n\n            var cancel_p = quickElement('p', clock_box);\n            cancel_p.className = 'calendar-cancel';\n            var cancel_link = quickElement('a', cancel_p, gettext('Cancel'), 'href', '#');\n            addEvent(cancel_link, 'click', function(e) {\n                e.preventDefault();\n                DateTimeShortcuts.dismissClock(num);\n            });\n\n            django.jQuery(document).bind('keyup', function(event) {\n                if (event.which === 27) {\n                    // ESC key closes popup\n                    DateTimeShortcuts.dismissClock(num);\n                    event.preventDefault();\n                }\n            });\n        },\n        openClock: function(num) {\n            var clock_box = document.getElementById(DateTimeShortcuts.clockDivName + num);\n            var clock_link = document.getElementById(DateTimeShortcuts.clockLinkName + num);\n\n            // Recalculate the clockbox position\n            // is it left-to-right or right-to-left layout ?\n            if (getStyle(document.body, 'direction') !== 'rtl') {\n                clock_box.style.left = findPosX(clock_link) + 17 + 'px';\n            }\n            else {\n                // since style's width is in em, it'd be tough to calculate\n                // px value of it. let's use an estimated px for now\n                // TODO: IE returns wrong value for findPosX when in rtl mode\n                //       (it returns as it was left aligned), needs to be fixed.\n                clock_box.style.left = findPosX(clock_link) - 110 + 'px';\n            }\n            clock_box.style.top = Math.max(0, findPosY(clock_link) - 30) + 'px';\n\n            // Show the clock box\n            clock_box.style.display = 'block';\n            addEvent(document, 'click', DateTimeShortcuts.dismissClockFunc[num]);\n        },\n        dismissClock: function(num) {\n            document.getElementById(DateTimeShortcuts.clockDivName + num).style.display = 'none';\n            removeEvent(document, 'click', DateTimeShortcuts.dismissClockFunc[num]);\n        },\n        handleClockQuicklink: function(num, val) {\n            var d;\n            if (val === -1) {\n                d = DateTimeShortcuts.now();\n            }\n            else {\n                d = new Date(1970, 1, 1, val, 0, 0, 0);\n            }\n            DateTimeShortcuts.clockInputs[num].value = d.strftime(get_format('TIME_INPUT_FORMATS')[0]);\n            DateTimeShortcuts.clockInputs[num].focus();\n            DateTimeShortcuts.dismissClock(num);\n        },\n        // Add calendar widget to a given field.\n        addCalendar: function(inp) {\n            var num = DateTimeShortcuts.calendars.length;\n\n            DateTimeShortcuts.calendarInputs[num] = inp;\n            DateTimeShortcuts.dismissCalendarFunc[num] = function() { DateTimeShortcuts.dismissCalendar(num); return true; };\n\n            // Shortcut links (calendar icon and \"Today\" link)\n            var shortcuts_span = document.createElement('span');\n            shortcuts_span.className = DateTimeShortcuts.shortCutsClass;\n            inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling);\n            var today_link = document.createElement('a');\n            today_link.setAttribute('href', '#');\n            today_link.appendChild(document.createTextNode(gettext('Today')));\n            addEvent(today_link, 'click', function(e) {\n                e.preventDefault();\n                DateTimeShortcuts.handleCalendarQuickLink(num, 0);\n            });\n            var cal_link = document.createElement('a');\n            cal_link.setAttribute('href', '#');\n            cal_link.id = DateTimeShortcuts.calendarLinkName + num;\n            addEvent(cal_link, 'click', function(e) {\n                e.preventDefault();\n                // avoid triggering the document click handler to dismiss the calendar\n                e.stopPropagation();\n                DateTimeShortcuts.openCalendar(num);\n            });\n            quickElement(\n                'span', cal_link, '',\n                'class', 'date-icon',\n                'title', gettext('Choose a Date')\n            );\n            shortcuts_span.appendChild(document.createTextNode('\\u00A0'));\n            shortcuts_span.appendChild(today_link);\n            shortcuts_span.appendChild(document.createTextNode('\\u00A0|\\u00A0'));\n            shortcuts_span.appendChild(cal_link);\n\n            // Create calendarbox div.\n            //\n            // Markup looks like:\n            //\n            // <div id=\"calendarbox3\" class=\"calendarbox module\">\n            //     <h2>\n            //           <a href=\"#\" class=\"link-previous\">&lsaquo;</a>\n            //           <a href=\"#\" class=\"link-next\">&rsaquo;</a> February 2003\n            //     </h2>\n            //     <div class=\"calendar\" id=\"calendarin3\">\n            //         <!-- (cal) -->\n            //     </div>\n            //     <div class=\"calendar-shortcuts\">\n            //          <a href=\"#\">Yesterday</a> | <a href=\"#\">Today</a> | <a href=\"#\">Tomorrow</a>\n            //     </div>\n            //     <p class=\"calendar-cancel\"><a href=\"#\">Cancel</a></p>\n            // </div>\n            var cal_box = document.createElement('div');\n            cal_box.style.display = 'none';\n            cal_box.style.position = 'absolute';\n            cal_box.className = 'calendarbox module';\n            cal_box.setAttribute('id', DateTimeShortcuts.calendarDivName1 + num);\n            document.body.appendChild(cal_box);\n            addEvent(cal_box, 'click', cancelEventPropagation);\n\n            // next-prev links\n            var cal_nav = quickElement('div', cal_box);\n            var cal_nav_prev = quickElement('a', cal_nav, '<', 'href', '#');\n            cal_nav_prev.className = 'calendarnav-previous';\n            addEvent(cal_nav_prev, 'click', function(e) {\n                e.preventDefault();\n                DateTimeShortcuts.drawPrev(num);\n            });\n\n            var cal_nav_next = quickElement('a', cal_nav, '>', 'href', '#');\n            cal_nav_next.className = 'calendarnav-next';\n            addEvent(cal_nav_next, 'click', function(e) {\n                e.preventDefault();\n                DateTimeShortcuts.drawNext(num);\n            });\n\n            // main box\n            var cal_main = quickElement('div', cal_box, '', 'id', DateTimeShortcuts.calendarDivName2 + num);\n            cal_main.className = 'calendar';\n            DateTimeShortcuts.calendars[num] = new Calendar(DateTimeShortcuts.calendarDivName2 + num, DateTimeShortcuts.handleCalendarCallback(num));\n            DateTimeShortcuts.calendars[num].drawCurrent();\n\n            // calendar shortcuts\n            var shortcuts = quickElement('div', cal_box);\n            shortcuts.className = 'calendar-shortcuts';\n            var day_link = quickElement('a', shortcuts, gettext('Yesterday'), 'href', '#');\n            addEvent(day_link, 'click', function(e) {\n                e.preventDefault();\n                DateTimeShortcuts.handleCalendarQuickLink(num, -1);\n            });\n            shortcuts.appendChild(document.createTextNode('\\u00A0|\\u00A0'));\n            day_link = quickElement('a', shortcuts, gettext('Today'), 'href', '#');\n            addEvent(day_link, 'click', function(e) {\n                e.preventDefault();\n                DateTimeShortcuts.handleCalendarQuickLink(num, 0);\n            });\n            shortcuts.appendChild(document.createTextNode('\\u00A0|\\u00A0'));\n            day_link = quickElement('a', shortcuts, gettext('Tomorrow'), 'href', '#');\n            addEvent(day_link, 'click', function(e) {\n                e.preventDefault();\n                DateTimeShortcuts.handleCalendarQuickLink(num, +1);\n            });\n\n            // cancel bar\n            var cancel_p = quickElement('p', cal_box);\n            cancel_p.className = 'calendar-cancel';\n            var cancel_link = quickElement('a', cancel_p, gettext('Cancel'), 'href', '#');\n            addEvent(cancel_link, 'click', function(e) {\n                e.preventDefault();\n                DateTimeShortcuts.dismissCalendar(num);\n            });\n            django.jQuery(document).bind('keyup', function(event) {\n                if (event.which === 27) {\n                    // ESC key closes popup\n                    DateTimeShortcuts.dismissCalendar(num);\n                    event.preventDefault();\n                }\n            });\n        },\n        openCalendar: function(num) {\n            var cal_box = document.getElementById(DateTimeShortcuts.calendarDivName1 + num);\n            var cal_link = document.getElementById(DateTimeShortcuts.calendarLinkName + num);\n            var inp = DateTimeShortcuts.calendarInputs[num];\n\n            // Determine if the current value in the input has a valid date.\n            // If so, draw the calendar with that date's year and month.\n            if (inp.value) {\n                var format = get_format('DATE_INPUT_FORMATS')[0];\n                var selected = inp.value.strptime(format);\n                var year = selected.getUTCFullYear();\n                var month = selected.getUTCMonth() + 1;\n                var re = /\\d{4}/;\n                if (re.test(year.toString()) && month >= 1 && month <= 12) {\n                    DateTimeShortcuts.calendars[num].drawDate(month, year, selected);\n                }\n            }\n\n            // Recalculate the clockbox position\n            // is it left-to-right or right-to-left layout ?\n            if (getStyle(document.body, 'direction') !== 'rtl') {\n                cal_box.style.left = findPosX(cal_link) + 17 + 'px';\n            }\n            else {\n                // since style's width is in em, it'd be tough to calculate\n                // px value of it. let's use an estimated px for now\n                // TODO: IE returns wrong value for findPosX when in rtl mode\n                //       (it returns as it was left aligned), needs to be fixed.\n                cal_box.style.left = findPosX(cal_link) - 180 + 'px';\n            }\n            cal_box.style.top = Math.max(0, findPosY(cal_link) - 75) + 'px';\n\n            cal_box.style.display = 'block';\n            addEvent(document, 'click', DateTimeShortcuts.dismissCalendarFunc[num]);\n        },\n        dismissCalendar: function(num) {\n            document.getElementById(DateTimeShortcuts.calendarDivName1 + num).style.display = 'none';\n            removeEvent(document, 'click', DateTimeShortcuts.dismissCalendarFunc[num]);\n        },\n        drawPrev: function(num) {\n            DateTimeShortcuts.calendars[num].drawPreviousMonth();\n        },\n        drawNext: function(num) {\n            DateTimeShortcuts.calendars[num].drawNextMonth();\n        },\n        handleCalendarCallback: function(num) {\n            var format = get_format('DATE_INPUT_FORMATS')[0];\n            // the format needs to be escaped a little\n            format = format.replace('\\\\', '\\\\\\\\');\n            format = format.replace('\\r', '\\\\r');\n            format = format.replace('\\n', '\\\\n');\n            format = format.replace('\\t', '\\\\t');\n            format = format.replace(\"'\", \"\\\\'\");\n            return function(y, m, d) {\n                DateTimeShortcuts.calendarInputs[num].value = new Date(y, m - 1, d).strftime(format);\n                DateTimeShortcuts.calendarInputs[num].focus();\n                document.getElementById(DateTimeShortcuts.calendarDivName1 + num).style.display = 'none';\n            };\n        },\n        handleCalendarQuickLink: function(num, offset) {\n            var d = DateTimeShortcuts.now();\n            d.setDate(d.getDate() + offset);\n            DateTimeShortcuts.calendarInputs[num].value = d.strftime(get_format('DATE_INPUT_FORMATS')[0]);\n            DateTimeShortcuts.calendarInputs[num].focus();\n            DateTimeShortcuts.dismissCalendar(num);\n        }\n    };\n\n    addEvent(window, 'load', DateTimeShortcuts.init);\n    window.DateTimeShortcuts = DateTimeShortcuts;\n})();\n"
  },
  {
    "path": "static_cdn/static_root/admin/js/admin/RelatedObjectLookups.js",
    "content": "/*global SelectBox, interpolate*/\n// Handles related-objects functionality: lookup link for raw_id_fields\n// and Add Another links.\n\n(function($) {\n    'use strict';\n\n    // IE doesn't accept periods or dashes in the window name, but the element IDs\n    // we use to generate popup window names may contain them, therefore we map them\n    // to allowed characters in a reversible way so that we can locate the correct\n    // element when the popup window is dismissed.\n    function id_to_windowname(text) {\n        text = text.replace(/\\./g, '__dot__');\n        text = text.replace(/\\-/g, '__dash__');\n        return text;\n    }\n\n    function windowname_to_id(text) {\n        text = text.replace(/__dot__/g, '.');\n        text = text.replace(/__dash__/g, '-');\n        return text;\n    }\n\n    function showAdminPopup(triggeringLink, name_regexp, add_popup) {\n        var name = triggeringLink.id.replace(name_regexp, '');\n        name = id_to_windowname(name);\n        var href = triggeringLink.href;\n        if (add_popup) {\n            if (href.indexOf('?') === -1) {\n                href += '?_popup=1';\n            } else {\n                href += '&_popup=1';\n            }\n        }\n        var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');\n        win.focus();\n        return false;\n    }\n\n    function showRelatedObjectLookupPopup(triggeringLink) {\n        return showAdminPopup(triggeringLink, /^lookup_/, true);\n    }\n\n    function dismissRelatedLookupPopup(win, chosenId) {\n        var name = windowname_to_id(win.name);\n        var elem = document.getElementById(name);\n        if (elem.className.indexOf('vManyToManyRawIdAdminField') !== -1 && elem.value) {\n            elem.value += ',' + chosenId;\n        } else {\n            document.getElementById(name).value = chosenId;\n        }\n        win.close();\n    }\n\n    function showRelatedObjectPopup(triggeringLink) {\n        return showAdminPopup(triggeringLink, /^(change|add|delete)_/, false);\n    }\n\n    function updateRelatedObjectLinks(triggeringLink) {\n        var $this = $(triggeringLink);\n        var siblings = $this.nextAll('.change-related, .delete-related');\n        if (!siblings.length) {\n            return;\n        }\n        var value = $this.val();\n        if (value) {\n            siblings.each(function() {\n                var elm = $(this);\n                elm.attr('href', elm.attr('data-href-template').replace('__fk__', value));\n            });\n        } else {\n            siblings.removeAttr('href');\n        }\n    }\n\n    function dismissAddRelatedObjectPopup(win, newId, newRepr) {\n        var name = windowname_to_id(win.name);\n        var elem = document.getElementById(name);\n        if (elem) {\n            var elemName = elem.nodeName.toUpperCase();\n            if (elemName === 'SELECT') {\n                elem.options[elem.options.length] = new Option(newRepr, newId, true, true);\n            } else if (elemName === 'INPUT') {\n                if (elem.className.indexOf('vManyToManyRawIdAdminField') !== -1 && elem.value) {\n                    elem.value += ',' + newId;\n                } else {\n                    elem.value = newId;\n                }\n            }\n            // Trigger a change event to update related links if required.\n            $(elem).trigger('change');\n        } else {\n            var toId = name + \"_to\";\n            var o = new Option(newRepr, newId);\n            SelectBox.add_to_cache(toId, o);\n            SelectBox.redisplay(toId);\n        }\n        win.close();\n    }\n\n    function dismissChangeRelatedObjectPopup(win, objId, newRepr, newId) {\n        var id = windowname_to_id(win.name).replace(/^edit_/, '');\n        var selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]);\n        var selects = $(selectsSelector);\n        selects.find('option').each(function() {\n            if (this.value === objId) {\n                this.textContent = newRepr;\n                this.value = newId;\n            }\n        });\n        win.close();\n    }\n\n    function dismissDeleteRelatedObjectPopup(win, objId) {\n        var id = windowname_to_id(win.name).replace(/^delete_/, '');\n        var selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]);\n        var selects = $(selectsSelector);\n        selects.find('option').each(function() {\n            if (this.value === objId) {\n                $(this).remove();\n            }\n        }).trigger('change');\n        win.close();\n    }\n\n    // Global for testing purposes\n    window.id_to_windowname = id_to_windowname;\n    window.windowname_to_id = windowname_to_id;\n\n    window.showRelatedObjectLookupPopup = showRelatedObjectLookupPopup;\n    window.dismissRelatedLookupPopup = dismissRelatedLookupPopup;\n    window.showRelatedObjectPopup = showRelatedObjectPopup;\n    window.updateRelatedObjectLinks = updateRelatedObjectLinks;\n    window.dismissAddRelatedObjectPopup = dismissAddRelatedObjectPopup;\n    window.dismissChangeRelatedObjectPopup = dismissChangeRelatedObjectPopup;\n    window.dismissDeleteRelatedObjectPopup = dismissDeleteRelatedObjectPopup;\n\n    // Kept for backward compatibility\n    window.showAddAnotherPopup = showRelatedObjectPopup;\n    window.dismissAddAnotherPopup = dismissAddRelatedObjectPopup;\n\n    $(document).ready(function() {\n        $(\"a[data-popup-opener]\").click(function(event) {\n            event.preventDefault();\n            opener.dismissRelatedLookupPopup(window, $(this).data(\"popup-opener\"));\n        });\n        $('body').on('click', '.related-widget-wrapper-link', function(e) {\n            e.preventDefault();\n            if (this.href) {\n                var event = $.Event('django:show-related', {href: this.href});\n                $(this).trigger(event);\n                if (!event.isDefaultPrevented()) {\n                    showRelatedObjectPopup(this);\n                }\n            }\n        });\n        $('body').on('change', '.related-widget-wrapper select', function(e) {\n            var event = $.Event('django:update-related');\n            $(this).trigger(event);\n            if (!event.isDefaultPrevented()) {\n                updateRelatedObjectLinks(this);\n            }\n        });\n        $('.related-widget-wrapper select').trigger('change');\n        $('body').on('click', '.related-lookup', function(e) {\n            e.preventDefault();\n            var event = $.Event('django:lookup-related');\n            $(this).trigger(event);\n            if (!event.isDefaultPrevented()) {\n                showRelatedObjectLookupPopup(this);\n            }\n        });\n    });\n\n})(django.jQuery);\n"
  },
  {
    "path": "static_cdn/static_root/admin/js/calendar.js",
    "content": "/*global gettext, pgettext, get_format, quickElement, removeChildren, addEvent*/\n/*\ncalendar.js - Calendar functions by Adrian Holovaty\ndepends on core.js for utility functions like removeChildren or quickElement\n*/\n\n(function() {\n    'use strict';\n    // CalendarNamespace -- Provides a collection of HTML calendar-related helper functions\n    var CalendarNamespace = {\n        monthsOfYear: [\n            gettext('January'),\n            gettext('February'),\n            gettext('March'),\n            gettext('April'),\n            gettext('May'),\n            gettext('June'),\n            gettext('July'),\n            gettext('August'),\n            gettext('September'),\n            gettext('October'),\n            gettext('November'),\n            gettext('December')\n        ],\n        daysOfWeek: [\n            pgettext('one letter Sunday', 'S'),\n            pgettext('one letter Monday', 'M'),\n            pgettext('one letter Tuesday', 'T'),\n            pgettext('one letter Wednesday', 'W'),\n            pgettext('one letter Thursday', 'T'),\n            pgettext('one letter Friday', 'F'),\n            pgettext('one letter Saturday', 'S')\n        ],\n        firstDayOfWeek: parseInt(get_format('FIRST_DAY_OF_WEEK')),\n        isLeapYear: function(year) {\n            return (((year % 4) === 0) && ((year % 100) !== 0 ) || ((year % 400) === 0));\n        },\n        getDaysInMonth: function(month, year) {\n            var days;\n            if (month === 1 || month === 3 || month === 5 || month === 7 || month === 8 || month === 10 || month === 12) {\n                days = 31;\n            }\n            else if (month === 4 || month === 6 || month === 9 || month === 11) {\n                days = 30;\n            }\n            else if (month === 2 && CalendarNamespace.isLeapYear(year)) {\n                days = 29;\n            }\n            else {\n                days = 28;\n            }\n            return days;\n        },\n        draw: function(month, year, div_id, callback, selected) { // month = 1-12, year = 1-9999\n            var today = new Date();\n            var todayDay = today.getDate();\n            var todayMonth = today.getMonth() + 1;\n            var todayYear = today.getFullYear();\n            var todayClass = '';\n\n            // Use UTC functions here because the date field does not contain time\n            // and using the UTC function variants prevent the local time offset\n            // from altering the date, specifically the day field.  For example:\n            //\n            // ```\n            // var x = new Date('2013-10-02');\n            // var day = x.getDate();\n            // ```\n            //\n            // The day variable above will be 1 instead of 2 in, say, US Pacific time\n            // zone.\n            var isSelectedMonth = false;\n            if (typeof selected !== 'undefined') {\n                isSelectedMonth = (selected.getUTCFullYear() === year && (selected.getUTCMonth() + 1) === month);\n            }\n\n            month = parseInt(month);\n            year = parseInt(year);\n            var calDiv = document.getElementById(div_id);\n            removeChildren(calDiv);\n            var calTable = document.createElement('table');\n            quickElement('caption', calTable, CalendarNamespace.monthsOfYear[month - 1] + ' ' + year);\n            var tableBody = quickElement('tbody', calTable);\n\n            // Draw days-of-week header\n            var tableRow = quickElement('tr', tableBody);\n            for (var i = 0; i < 7; i++) {\n                quickElement('th', tableRow, CalendarNamespace.daysOfWeek[(i + CalendarNamespace.firstDayOfWeek) % 7]);\n            }\n\n            var startingPos = new Date(year, month - 1, 1 - CalendarNamespace.firstDayOfWeek).getDay();\n            var days = CalendarNamespace.getDaysInMonth(month, year);\n\n            var nonDayCell;\n\n            // Draw blanks before first of month\n            tableRow = quickElement('tr', tableBody);\n            for (i = 0; i < startingPos; i++) {\n                nonDayCell = quickElement('td', tableRow, ' ');\n                nonDayCell.className = \"nonday\";\n            }\n\n            function calendarMonth(y, m) {\n                function onClick(e) {\n                    e.preventDefault();\n                    callback(y, m, django.jQuery(this).text());\n                }\n                return onClick;\n            }\n\n            // Draw days of month\n            var currentDay = 1;\n            for (i = startingPos; currentDay <= days; i++) {\n                if (i % 7 === 0 && currentDay !== 1) {\n                    tableRow = quickElement('tr', tableBody);\n                }\n                if ((currentDay === todayDay) && (month === todayMonth) && (year === todayYear)) {\n                    todayClass = 'today';\n                } else {\n                    todayClass = '';\n                }\n\n                // use UTC function; see above for explanation.\n                if (isSelectedMonth && currentDay === selected.getUTCDate()) {\n                    if (todayClass !== '') {\n                        todayClass += \" \";\n                    }\n                    todayClass += \"selected\";\n                }\n\n                var cell = quickElement('td', tableRow, '', 'class', todayClass);\n                var link = quickElement('a', cell, currentDay, 'href', '#');\n                addEvent(link, 'click', calendarMonth(year, month));\n                currentDay++;\n            }\n\n            // Draw blanks after end of month (optional, but makes for valid code)\n            while (tableRow.childNodes.length < 7) {\n                nonDayCell = quickElement('td', tableRow, ' ');\n                nonDayCell.className = \"nonday\";\n            }\n\n            calDiv.appendChild(calTable);\n        }\n    };\n\n    // Calendar -- A calendar instance\n    function Calendar(div_id, callback, selected) {\n        // div_id (string) is the ID of the element in which the calendar will\n        //     be displayed\n        // callback (string) is the name of a JavaScript function that will be\n        //     called with the parameters (year, month, day) when a day in the\n        //     calendar is clicked\n        this.div_id = div_id;\n        this.callback = callback;\n        this.today = new Date();\n        this.currentMonth = this.today.getMonth() + 1;\n        this.currentYear = this.today.getFullYear();\n        if (typeof selected !== 'undefined') {\n            this.selected = selected;\n        }\n    }\n    Calendar.prototype = {\n        drawCurrent: function() {\n            CalendarNamespace.draw(this.currentMonth, this.currentYear, this.div_id, this.callback, this.selected);\n        },\n        drawDate: function(month, year, selected) {\n            this.currentMonth = month;\n            this.currentYear = year;\n\n            if(selected) {\n                this.selected = selected;\n            }\n\n            this.drawCurrent();\n        },\n        drawPreviousMonth: function() {\n            if (this.currentMonth === 1) {\n                this.currentMonth = 12;\n                this.currentYear--;\n            }\n            else {\n                this.currentMonth--;\n            }\n            this.drawCurrent();\n        },\n        drawNextMonth: function() {\n            if (this.currentMonth === 12) {\n                this.currentMonth = 1;\n                this.currentYear++;\n            }\n            else {\n                this.currentMonth++;\n            }\n            this.drawCurrent();\n        },\n        drawPreviousYear: function() {\n            this.currentYear--;\n            this.drawCurrent();\n        },\n        drawNextYear: function() {\n            this.currentYear++;\n            this.drawCurrent();\n        }\n    };\n    window.Calendar = Calendar;\n    window.CalendarNamespace = CalendarNamespace;\n})();\n"
  },
  {
    "path": "static_cdn/static_root/admin/js/cancel.js",
    "content": "(function($) {\n    'use strict';\n    $(function() {\n        $('.cancel-link').click(function(e) {\n            e.preventDefault();\n            window.history.back();\n        });\n    });\n})(django.jQuery);\n"
  },
  {
    "path": "static_cdn/static_root/admin/js/change_form.js",
    "content": "/*global showAddAnotherPopup, showRelatedObjectLookupPopup showRelatedObjectPopup updateRelatedObjectLinks*/\n\n(function($) {\n    'use strict';\n    $(document).ready(function() {\n        var modelName = $('#django-admin-form-add-constants').data('modelName');\n        $('body').on('click', '.add-another', function(e) {\n            e.preventDefault();\n            var event = $.Event('django:add-another-related');\n            $(this).trigger(event);\n            if (!event.isDefaultPrevented()) {\n                showAddAnotherPopup(this);\n            }\n        });\n\n        if (modelName) {\n            $('form#' + modelName + '_form :input:visible:enabled:first').focus();\n        }\n    });\n})(django.jQuery);\n"
  },
  {
    "path": "static_cdn/static_root/admin/js/collapse.js",
    "content": "/*global gettext*/\n(function($) {\n    'use strict';\n    $(document).ready(function() {\n        // Add anchor tag for Show/Hide link\n        $(\"fieldset.collapse\").each(function(i, elem) {\n            // Don't hide if fields in this fieldset have errors\n            if ($(elem).find(\"div.errors\").length === 0) {\n                $(elem).addClass(\"collapsed\").find(\"h2\").first().append(' (<a id=\"fieldsetcollapser' +\n                    i + '\" class=\"collapse-toggle\" href=\"#\">' + gettext(\"Show\") +\n                    '</a>)');\n            }\n        });\n        // Add toggle to anchor tag\n        $(\"fieldset.collapse a.collapse-toggle\").click(function(ev) {\n            if ($(this).closest(\"fieldset\").hasClass(\"collapsed\")) {\n                // Show\n                $(this).text(gettext(\"Hide\")).closest(\"fieldset\").removeClass(\"collapsed\").trigger(\"show.fieldset\", [$(this).attr(\"id\")]);\n            } else {\n                // Hide\n                $(this).text(gettext(\"Show\")).closest(\"fieldset\").addClass(\"collapsed\").trigger(\"hide.fieldset\", [$(this).attr(\"id\")]);\n            }\n            return false;\n        });\n    });\n})(django.jQuery);\n"
  },
  {
    "path": "static_cdn/static_root/admin/js/core.js",
    "content": "// Core javascript helper functions\n\n// basic browser identification & version\nvar isOpera = (navigator.userAgent.indexOf(\"Opera\") >= 0) && parseFloat(navigator.appVersion);\nvar isIE = ((document.all) && (!isOpera)) && parseFloat(navigator.appVersion.split(\"MSIE \")[1].split(\";\")[0]);\n\n// Cross-browser event handlers.\nfunction addEvent(obj, evType, fn) {\n    'use strict';\n    if (obj.addEventListener) {\n        obj.addEventListener(evType, fn, false);\n        return true;\n    } else if (obj.attachEvent) {\n        var r = obj.attachEvent(\"on\" + evType, fn);\n        return r;\n    } else {\n        return false;\n    }\n}\n\nfunction removeEvent(obj, evType, fn) {\n    'use strict';\n    if (obj.removeEventListener) {\n        obj.removeEventListener(evType, fn, false);\n        return true;\n    } else if (obj.detachEvent) {\n        obj.detachEvent(\"on\" + evType, fn);\n        return true;\n    } else {\n        return false;\n    }\n}\n\nfunction cancelEventPropagation(e) {\n    'use strict';\n    if (!e) {\n        e = window.event;\n    }\n    e.cancelBubble = true;\n    if (e.stopPropagation) {\n        e.stopPropagation();\n    }\n}\n\n// quickElement(tagType, parentReference [, textInChildNode, attribute, attributeValue ...]);\nfunction quickElement() {\n    'use strict';\n    var obj = document.createElement(arguments[0]);\n    if (arguments[2]) {\n        var textNode = document.createTextNode(arguments[2]);\n        obj.appendChild(textNode);\n    }\n    var len = arguments.length;\n    for (var i = 3; i < len; i += 2) {\n        obj.setAttribute(arguments[i], arguments[i + 1]);\n    }\n    arguments[1].appendChild(obj);\n    return obj;\n}\n\n// \"a\" is reference to an object\nfunction removeChildren(a) {\n    'use strict';\n    while (a.hasChildNodes()) {\n        a.removeChild(a.lastChild);\n    }\n}\n\n// ----------------------------------------------------------------------------\n// Find-position functions by PPK\n// See http://www.quirksmode.org/js/findpos.html\n// ----------------------------------------------------------------------------\nfunction findPosX(obj) {\n    'use strict';\n    var curleft = 0;\n    if (obj.offsetParent) {\n        while (obj.offsetParent) {\n            curleft += obj.offsetLeft - ((isOpera) ? 0 : obj.scrollLeft);\n            obj = obj.offsetParent;\n        }\n        // IE offsetParent does not include the top-level\n        if (isIE && obj.parentElement) {\n            curleft += obj.offsetLeft - obj.scrollLeft;\n        }\n    } else if (obj.x) {\n        curleft += obj.x;\n    }\n    return curleft;\n}\n\nfunction findPosY(obj) {\n    'use strict';\n    var curtop = 0;\n    if (obj.offsetParent) {\n        while (obj.offsetParent) {\n            curtop += obj.offsetTop - ((isOpera) ? 0 : obj.scrollTop);\n            obj = obj.offsetParent;\n        }\n        // IE offsetParent does not include the top-level\n        if (isIE && obj.parentElement) {\n            curtop += obj.offsetTop - obj.scrollTop;\n        }\n    } else if (obj.y) {\n        curtop += obj.y;\n    }\n    return curtop;\n}\n\n//-----------------------------------------------------------------------------\n// Date object extensions\n// ----------------------------------------------------------------------------\n(function() {\n    'use strict';\n    Date.prototype.getTwelveHours = function() {\n        var hours = this.getHours();\n        if (hours === 0) {\n            return 12;\n        }\n        else {\n            return hours <= 12 ? hours : hours - 12;\n        }\n    };\n\n    Date.prototype.getTwoDigitMonth = function() {\n        return (this.getMonth() < 9) ? '0' + (this.getMonth() + 1) : (this.getMonth() + 1);\n    };\n\n    Date.prototype.getTwoDigitDate = function() {\n        return (this.getDate() < 10) ? '0' + this.getDate() : this.getDate();\n    };\n\n    Date.prototype.getTwoDigitTwelveHour = function() {\n        return (this.getTwelveHours() < 10) ? '0' + this.getTwelveHours() : this.getTwelveHours();\n    };\n\n    Date.prototype.getTwoDigitHour = function() {\n        return (this.getHours() < 10) ? '0' + this.getHours() : this.getHours();\n    };\n\n    Date.prototype.getTwoDigitMinute = function() {\n        return (this.getMinutes() < 10) ? '0' + this.getMinutes() : this.getMinutes();\n    };\n\n    Date.prototype.getTwoDigitSecond = function() {\n        return (this.getSeconds() < 10) ? '0' + this.getSeconds() : this.getSeconds();\n    };\n\n    Date.prototype.getHourMinute = function() {\n        return this.getTwoDigitHour() + ':' + this.getTwoDigitMinute();\n    };\n\n    Date.prototype.getHourMinuteSecond = function() {\n        return this.getTwoDigitHour() + ':' + this.getTwoDigitMinute() + ':' + this.getTwoDigitSecond();\n    };\n\n    Date.prototype.getFullMonthName = function() {\n        return typeof window.CalendarNamespace === \"undefined\"\n            ? this.getTwoDigitMonth()\n            : window.CalendarNamespace.monthsOfYear[this.getMonth()];\n    };\n\n    Date.prototype.strftime = function(format) {\n        var fields = {\n            B: this.getFullMonthName(),\n            c: this.toString(),\n            d: this.getTwoDigitDate(),\n            H: this.getTwoDigitHour(),\n            I: this.getTwoDigitTwelveHour(),\n            m: this.getTwoDigitMonth(),\n            M: this.getTwoDigitMinute(),\n            p: (this.getHours() >= 12) ? 'PM' : 'AM',\n            S: this.getTwoDigitSecond(),\n            w: '0' + this.getDay(),\n            x: this.toLocaleDateString(),\n            X: this.toLocaleTimeString(),\n            y: ('' + this.getFullYear()).substr(2, 4),\n            Y: '' + this.getFullYear(),\n            '%': '%'\n        };\n        var result = '', i = 0;\n        while (i < format.length) {\n            if (format.charAt(i) === '%') {\n                result = result + fields[format.charAt(i + 1)];\n                ++i;\n            }\n            else {\n                result = result + format.charAt(i);\n            }\n            ++i;\n        }\n        return result;\n    };\n\n// ----------------------------------------------------------------------------\n// String object extensions\n// ----------------------------------------------------------------------------\n    String.prototype.pad_left = function(pad_length, pad_string) {\n        var new_string = this;\n        for (var i = 0; new_string.length < pad_length; i++) {\n            new_string = pad_string + new_string;\n        }\n        return new_string;\n    };\n\n    String.prototype.strptime = function(format) {\n        var split_format = format.split(/[.\\-/]/);\n        var date = this.split(/[.\\-/]/);\n        var i = 0;\n        var day, month, year;\n        while (i < split_format.length) {\n            switch (split_format[i]) {\n                case \"%d\":\n                    day = date[i];\n                    break;\n                case \"%m\":\n                    month = date[i] - 1;\n                    break;\n                case \"%Y\":\n                    year = date[i];\n                    break;\n                case \"%y\":\n                    year = date[i];\n                    break;\n            }\n            ++i;\n        }\n        // Create Date object from UTC since the parsed value is supposed to be\n        // in UTC, not local time. Also, the calendar uses UTC functions for\n        // date extraction.\n        return new Date(Date.UTC(year, month, day));\n    };\n\n})();\n// ----------------------------------------------------------------------------\n// Get the computed style for and element\n// ----------------------------------------------------------------------------\nfunction getStyle(oElm, strCssRule) {\n    'use strict';\n    var strValue = \"\";\n    if(document.defaultView && document.defaultView.getComputedStyle) {\n        strValue = document.defaultView.getComputedStyle(oElm, \"\").getPropertyValue(strCssRule);\n    }\n    else if(oElm.currentStyle) {\n        strCssRule = strCssRule.replace(/\\-(\\w)/g, function(strMatch, p1) {\n            return p1.toUpperCase();\n        });\n        strValue = oElm.currentStyle[strCssRule];\n    }\n    return strValue;\n}\n"
  },
  {
    "path": "static_cdn/static_root/admin/js/inlines.js",
    "content": "/*global DateTimeShortcuts, SelectFilter*/\n/**\n * Django admin inlines\n *\n * Based on jQuery Formset 1.1\n * @author Stanislaus Madueke (stan DOT madueke AT gmail DOT com)\n * @requires jQuery 1.2.6 or later\n *\n * Copyright (c) 2009, Stanislaus Madueke\n * All rights reserved.\n *\n * Spiced up with Code from Zain Memon's GSoC project 2009\n * and modified for Django by Jannis Leidel, Travis Swicegood and Julien Phalip.\n *\n * Licensed under the New BSD License\n * See: http://www.opensource.org/licenses/bsd-license.php\n */\n(function($) {\n    'use strict';\n    $.fn.formset = function(opts) {\n        var options = $.extend({}, $.fn.formset.defaults, opts);\n        var $this = $(this);\n        var $parent = $this.parent();\n        var updateElementIndex = function(el, prefix, ndx) {\n            var id_regex = new RegExp(\"(\" + prefix + \"-(\\\\d+|__prefix__))\");\n            var replacement = prefix + \"-\" + ndx;\n            if ($(el).prop(\"for\")) {\n                $(el).prop(\"for\", $(el).prop(\"for\").replace(id_regex, replacement));\n            }\n            if (el.id) {\n                el.id = el.id.replace(id_regex, replacement);\n            }\n            if (el.name) {\n                el.name = el.name.replace(id_regex, replacement);\n            }\n        };\n        var totalForms = $(\"#id_\" + options.prefix + \"-TOTAL_FORMS\").prop(\"autocomplete\", \"off\");\n        var nextIndex = parseInt(totalForms.val(), 10);\n        var maxForms = $(\"#id_\" + options.prefix + \"-MAX_NUM_FORMS\").prop(\"autocomplete\", \"off\");\n        // only show the add button if we are allowed to add more items,\n        // note that max_num = None translates to a blank string.\n        var showAddButton = maxForms.val() === '' || (maxForms.val() - totalForms.val()) > 0;\n        $this.each(function(i) {\n            $(this).not(\".\" + options.emptyCssClass).addClass(options.formCssClass);\n        });\n        if ($this.length && showAddButton) {\n            var addButton = options.addButton;\n            if (addButton === null) {\n                if ($this.prop(\"tagName\") === \"TR\") {\n                    // If forms are laid out as table rows, insert the\n                    // \"add\" button in a new table row:\n                    var numCols = this.eq(-1).children().length;\n                    $parent.append('<tr class=\"' + options.addCssClass + '\"><td colspan=\"' + numCols + '\"><a href=\"#\">' + options.addText + \"</a></tr>\");\n                    addButton = $parent.find(\"tr:last a\");\n                } else {\n                    // Otherwise, insert it immediately after the last form:\n                    $this.filter(\":last\").after('<div class=\"' + options.addCssClass + '\"><a href=\"#\">' + options.addText + \"</a></div>\");\n                    addButton = $this.filter(\":last\").next().find(\"a\");\n                }\n            }\n            addButton.click(function(e) {\n                e.preventDefault();\n                var template = $(\"#\" + options.prefix + \"-empty\");\n                var row = template.clone(true);\n                row.removeClass(options.emptyCssClass)\n                .addClass(options.formCssClass)\n                .attr(\"id\", options.prefix + \"-\" + nextIndex);\n                if (row.is(\"tr\")) {\n                    // If the forms are laid out in table rows, insert\n                    // the remove button into the last table cell:\n                    row.children(\":last\").append('<div><a class=\"' + options.deleteCssClass + '\" href=\"#\">' + options.deleteText + \"</a></div>\");\n                } else if (row.is(\"ul\") || row.is(\"ol\")) {\n                    // If they're laid out as an ordered/unordered list,\n                    // insert an <li> after the last list item:\n                    row.append('<li><a class=\"' + options.deleteCssClass + '\" href=\"#\">' + options.deleteText + \"</a></li>\");\n                } else {\n                    // Otherwise, just insert the remove button as the\n                    // last child element of the form's container:\n                    row.children(\":first\").append('<span><a class=\"' + options.deleteCssClass + '\" href=\"#\">' + options.deleteText + \"</a></span>\");\n                }\n                row.find(\"*\").each(function() {\n                    updateElementIndex(this, options.prefix, totalForms.val());\n                });\n                // Insert the new form when it has been fully edited\n                row.insertBefore($(template));\n                // Update number of total forms\n                $(totalForms).val(parseInt(totalForms.val(), 10) + 1);\n                nextIndex += 1;\n                // Hide add button in case we've hit the max, except we want to add infinitely\n                if ((maxForms.val() !== '') && (maxForms.val() - totalForms.val()) <= 0) {\n                    addButton.parent().hide();\n                }\n                // The delete button of each row triggers a bunch of other things\n                row.find(\"a.\" + options.deleteCssClass).click(function(e1) {\n                    e1.preventDefault();\n                    // Remove the parent form containing this button:\n                    row.remove();\n                    nextIndex -= 1;\n                    // If a post-delete callback was provided, call it with the deleted form:\n                    if (options.removed) {\n                        options.removed(row);\n                    }\n                    $(document).trigger('formset:removed', [row, options.prefix]);\n                    // Update the TOTAL_FORMS form count.\n                    var forms = $(\".\" + options.formCssClass);\n                    $(\"#id_\" + options.prefix + \"-TOTAL_FORMS\").val(forms.length);\n                    // Show add button again once we drop below max\n                    if ((maxForms.val() === '') || (maxForms.val() - forms.length) > 0) {\n                        addButton.parent().show();\n                    }\n                    // Also, update names and ids for all remaining form controls\n                    // so they remain in sequence:\n                    var i, formCount;\n                    var updateElementCallback = function() {\n                        updateElementIndex(this, options.prefix, i);\n                    };\n                    for (i = 0, formCount = forms.length; i < formCount; i++) {\n                        updateElementIndex($(forms).get(i), options.prefix, i);\n                        $(forms.get(i)).find(\"*\").each(updateElementCallback);\n                    }\n                });\n                // If a post-add callback was supplied, call it with the added form:\n                if (options.added) {\n                    options.added(row);\n                }\n                $(document).trigger('formset:added', [row, options.prefix]);\n            });\n        }\n        return this;\n    };\n\n    /* Setup plugin defaults */\n    $.fn.formset.defaults = {\n        prefix: \"form\",          // The form prefix for your django formset\n        addText: \"add another\",      // Text for the add link\n        deleteText: \"remove\",      // Text for the delete link\n        addCssClass: \"add-row\",      // CSS class applied to the add link\n        deleteCssClass: \"delete-row\",  // CSS class applied to the delete link\n        emptyCssClass: \"empty-row\",    // CSS class applied to the empty row\n        formCssClass: \"dynamic-form\",  // CSS class applied to each form in a formset\n        added: null,          // Function called each time a new form is added\n        removed: null,          // Function called each time a form is deleted\n        addButton: null       // Existing add button to use\n    };\n\n\n    // Tabular inlines ---------------------------------------------------------\n    $.fn.tabularFormset = function(options) {\n        var $rows = $(this);\n        var alternatingRows = function(row) {\n            $($rows.selector).not(\".add-row\").removeClass(\"row1 row2\")\n            .filter(\":even\").addClass(\"row1\").end()\n            .filter(\":odd\").addClass(\"row2\");\n        };\n\n        var reinitDateTimeShortCuts = function() {\n            // Reinitialize the calendar and clock widgets by force\n            if (typeof DateTimeShortcuts !== \"undefined\") {\n                $(\".datetimeshortcuts\").remove();\n                DateTimeShortcuts.init();\n            }\n        };\n\n        var updateSelectFilter = function() {\n            // If any SelectFilter widgets are a part of the new form,\n            // instantiate a new SelectFilter instance for it.\n            if (typeof SelectFilter !== 'undefined') {\n                $('.selectfilter').each(function(index, value) {\n                    var namearr = value.name.split('-');\n                    SelectFilter.init(value.id, namearr[namearr.length - 1], false);\n                });\n                $('.selectfilterstacked').each(function(index, value) {\n                    var namearr = value.name.split('-');\n                    SelectFilter.init(value.id, namearr[namearr.length - 1], true);\n                });\n            }\n        };\n\n        var initPrepopulatedFields = function(row) {\n            row.find('.prepopulated_field').each(function() {\n                var field = $(this),\n                    input = field.find('input, select, textarea'),\n                    dependency_list = input.data('dependency_list') || [],\n                    dependencies = [];\n                $.each(dependency_list, function(i, field_name) {\n                    dependencies.push('#' + row.find('.field-' + field_name).find('input, select, textarea').attr('id'));\n                });\n                if (dependencies.length) {\n                    input.prepopulate(dependencies, input.attr('maxlength'));\n                }\n            });\n        };\n\n        $rows.formset({\n            prefix: options.prefix,\n            addText: options.addText,\n            formCssClass: \"dynamic-\" + options.prefix,\n            deleteCssClass: \"inline-deletelink\",\n            deleteText: options.deleteText,\n            emptyCssClass: \"empty-form\",\n            removed: alternatingRows,\n            added: function(row) {\n                initPrepopulatedFields(row);\n                reinitDateTimeShortCuts();\n                updateSelectFilter();\n                alternatingRows(row);\n            },\n            addButton: options.addButton\n        });\n\n        return $rows;\n    };\n\n    // Stacked inlines ---------------------------------------------------------\n    $.fn.stackedFormset = function(options) {\n        var $rows = $(this);\n        var updateInlineLabel = function(row) {\n            $($rows.selector).find(\".inline_label\").each(function(i) {\n                var count = i + 1;\n                $(this).html($(this).html().replace(/(#\\d+)/g, \"#\" + count));\n            });\n        };\n\n        var reinitDateTimeShortCuts = function() {\n            // Reinitialize the calendar and clock widgets by force, yuck.\n            if (typeof DateTimeShortcuts !== \"undefined\") {\n                $(\".datetimeshortcuts\").remove();\n                DateTimeShortcuts.init();\n            }\n        };\n\n        var updateSelectFilter = function() {\n            // If any SelectFilter widgets were added, instantiate a new instance.\n            if (typeof SelectFilter !== \"undefined\") {\n                $(\".selectfilter\").each(function(index, value) {\n                    var namearr = value.name.split('-');\n                    SelectFilter.init(value.id, namearr[namearr.length - 1], false);\n                });\n                $(\".selectfilterstacked\").each(function(index, value) {\n                    var namearr = value.name.split('-');\n                    SelectFilter.init(value.id, namearr[namearr.length - 1], true);\n                });\n            }\n        };\n\n        var initPrepopulatedFields = function(row) {\n            row.find('.prepopulated_field').each(function() {\n                var field = $(this),\n                    input = field.find('input, select, textarea'),\n                    dependency_list = input.data('dependency_list') || [],\n                    dependencies = [];\n                $.each(dependency_list, function(i, field_name) {\n                    dependencies.push('#' + row.find('.form-row .field-' + field_name).find('input, select, textarea').attr('id'));\n                });\n                if (dependencies.length) {\n                    input.prepopulate(dependencies, input.attr('maxlength'));\n                }\n            });\n        };\n\n        $rows.formset({\n            prefix: options.prefix,\n            addText: options.addText,\n            formCssClass: \"dynamic-\" + options.prefix,\n            deleteCssClass: \"inline-deletelink\",\n            deleteText: options.deleteText,\n            emptyCssClass: \"empty-form\",\n            removed: updateInlineLabel,\n            added: function(row) {\n                initPrepopulatedFields(row);\n                reinitDateTimeShortCuts();\n                updateSelectFilter();\n                updateInlineLabel(row);\n            },\n            addButton: options.addButton\n        });\n\n        return $rows;\n    };\n\n    $(document).ready(function() {\n        $(\".js-inline-admin-formset\").each(function() {\n            var data = $(this).data(),\n                inlineOptions = data.inlineFormset;\n            switch(data.inlineType) {\n            case \"stacked\":\n                $(inlineOptions.name + \"-group .inline-related\").stackedFormset(inlineOptions.options);\n                break;\n            case \"tabular\":\n                $(inlineOptions.name + \"-group .tabular.inline-related tbody tr\").tabularFormset(inlineOptions.options);\n                break;\n            }\n        });\n    });\n})(django.jQuery);\n"
  },
  {
    "path": "static_cdn/static_root/admin/js/jquery.init.js",
    "content": "/*global django:true, jQuery:false*/\n/* Puts the included jQuery into our own namespace using noConflict and passing\n * it 'true'. This ensures that the included jQuery doesn't pollute the global\n * namespace (i.e. this preserves pre-existing values for both window.$ and\n * window.jQuery).\n */\nvar django = django || {};\ndjango.jQuery = jQuery.noConflict(true);\n"
  },
  {
    "path": "static_cdn/static_root/admin/js/popup_response.js",
    "content": "/*global opener */\n(function() {\n    'use strict';\n    var initData = JSON.parse(document.getElementById('django-admin-popup-response-constants').dataset.popupResponse);\n    switch(initData.action) {\n    case 'change':\n        opener.dismissChangeRelatedObjectPopup(window, initData.value, initData.obj, initData.new_value);\n        break;\n    case 'delete':\n        opener.dismissDeleteRelatedObjectPopup(window, initData.value);\n        break;\n    default:\n        opener.dismissAddRelatedObjectPopup(window, initData.value, initData.obj);\n        break;\n    }\n})();\n"
  },
  {
    "path": "static_cdn/static_root/admin/js/prepopulate.js",
    "content": "/*global URLify*/\n(function($) {\n    'use strict';\n    $.fn.prepopulate = function(dependencies, maxLength, allowUnicode) {\n        /*\n            Depends on urlify.js\n            Populates a selected field with the values of the dependent fields,\n            URLifies and shortens the string.\n            dependencies - array of dependent fields ids\n            maxLength - maximum length of the URLify'd string\n            allowUnicode - Unicode support of the URLify'd string\n        */\n        return this.each(function() {\n            var prepopulatedField = $(this);\n\n            var populate = function() {\n                // Bail if the field's value has been changed by the user\n                if (prepopulatedField.data('_changed')) {\n                    return;\n                }\n\n                var values = [];\n                $.each(dependencies, function(i, field) {\n                    field = $(field);\n                    if (field.val().length > 0) {\n                        values.push(field.val());\n                    }\n                });\n                prepopulatedField.val(URLify(values.join(' '), maxLength, allowUnicode));\n            };\n\n            prepopulatedField.data('_changed', false);\n            prepopulatedField.change(function() {\n                prepopulatedField.data('_changed', true);\n            });\n\n            if (!prepopulatedField.val()) {\n                $(dependencies.join(',')).keyup(populate).change(populate).focus(populate);\n            }\n        });\n    };\n})(django.jQuery);\n"
  },
  {
    "path": "static_cdn/static_root/admin/js/prepopulate_init.js",
    "content": "(function($) {\n    'use strict';\n    var fields = $('#django-admin-prepopulated-fields-constants').data('prepopulatedFields');\n    $.each(fields, function(index, field) {\n        $('.empty-form .form-row .field-' + field.name + ', .empty-form.form-row .field-' + field.name).addClass('prepopulated_field');\n        $(field.id).data('dependency_list', field.dependency_list).prepopulate(\n            field.dependency_ids, field.maxLength, field.allowUnicode\n        );\n    });\n})(django.jQuery);\n"
  },
  {
    "path": "static_cdn/static_root/admin/js/timeparse.js",
    "content": "(function() {\n    'use strict';\n    var timeParsePatterns = [\n        // 9\n        {\n            re: /^\\d{1,2}$/i,\n            handler: function(bits) {\n                if (bits[0].length === 1) {\n                    return '0' + bits[0] + ':00';\n                } else {\n                    return bits[0] + ':00';\n                }\n            }\n        },\n        // 13:00\n        {\n            re: /^\\d{2}[:.]\\d{2}$/i,\n            handler: function(bits) {\n                return bits[0].replace('.', ':');\n            }\n        },\n        // 9:00\n        {\n            re: /^\\d[:.]\\d{2}$/i,\n            handler: function(bits) {\n                return '0' + bits[0].replace('.', ':');\n            }\n        },\n        // 3 am / 3 a.m. / 3am\n        {\n            re: /^(\\d+)\\s*([ap])(?:.?m.?)?$/i,\n            handler: function(bits) {\n                var hour = parseInt(bits[1]);\n                if (hour === 12) {\n                    hour = 0;\n                }\n                if (bits[2].toLowerCase() === 'p') {\n                    if (hour === 12) {\n                        hour = 0;\n                    }\n                    return (hour + 12) + ':00';\n                } else {\n                    if (hour < 10) {\n                        return '0' + hour + ':00';\n                    } else {\n                        return hour + ':00';\n                    }\n                }\n            }\n        },\n        // 3.30 am / 3:15 a.m. / 3.00am\n        {\n            re: /^(\\d+)[.:](\\d{2})\\s*([ap]).?m.?$/i,\n            handler: function(bits) {\n                var hour = parseInt(bits[1]);\n                var mins = parseInt(bits[2]);\n                if (mins < 10) {\n                    mins = '0' + mins;\n                }\n                if (hour === 12) {\n                    hour = 0;\n                }\n                if (bits[3].toLowerCase() === 'p') {\n                    if (hour === 12) {\n                        hour = 0;\n                    }\n                    return (hour + 12) + ':' + mins;\n                } else {\n                    if (hour < 10) {\n                        return '0' + hour + ':' + mins;\n                    } else {\n                        return hour + ':' + mins;\n                    }\n                }\n            }\n        },\n        // noon\n        {\n            re: /^no/i,\n            handler: function(bits) {\n                return '12:00';\n            }\n        },\n        // midnight\n        {\n            re: /^mid/i,\n            handler: function(bits) {\n                return '00:00';\n            }\n        }\n    ];\n\n    function parseTimeString(s) {\n        for (var i = 0; i < timeParsePatterns.length; i++) {\n            var re = timeParsePatterns[i].re;\n            var handler = timeParsePatterns[i].handler;\n            var bits = re.exec(s);\n            if (bits) {\n                return handler(bits);\n            }\n        }\n        return s;\n    }\n\n    window.parseTimeString = parseTimeString;\n})();\n"
  },
  {
    "path": "static_cdn/static_root/admin/js/urlify.js",
    "content": "/*global XRegExp*/\n(function() {\n    'use strict';\n\n    var LATIN_MAP = {\n        'À': 'A', 'Á': 'A', 'Â': 'A', 'Ã': 'A', 'Ä': 'A', 'Å': 'A', 'Æ': 'AE',\n        'Ç': 'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E', 'Ì': 'I', 'Í': 'I',\n        'Î': 'I', 'Ï': 'I', 'Ð': 'D', 'Ñ': 'N', 'Ò': 'O', 'Ó': 'O', 'Ô': 'O',\n        'Õ': 'O', 'Ö': 'O', 'Ő': 'O', 'Ø': 'O', 'Ù': 'U', 'Ú': 'U', 'Û': 'U',\n        'Ü': 'U', 'Ű': 'U', 'Ý': 'Y', 'Þ': 'TH', 'Ÿ': 'Y', 'ß': 'ss', 'à': 'a',\n        'á': 'a', 'â': 'a', 'ã': 'a', 'ä': 'a', 'å': 'a', 'æ': 'ae', 'ç': 'c',\n        'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e', 'ì': 'i', 'í': 'i', 'î': 'i',\n        'ï': 'i', 'ð': 'd', 'ñ': 'n', 'ò': 'o', 'ó': 'o', 'ô': 'o', 'õ': 'o',\n        'ö': 'o', 'ő': 'o', 'ø': 'o', 'ù': 'u', 'ú': 'u', 'û': 'u', 'ü': 'u',\n        'ű': 'u', 'ý': 'y', 'þ': 'th', 'ÿ': 'y'\n    };\n    var LATIN_SYMBOLS_MAP = {\n        '©': '(c)'\n    };\n    var GREEK_MAP = {\n        'α': 'a', 'β': 'b', 'γ': 'g', 'δ': 'd', 'ε': 'e', 'ζ': 'z', 'η': 'h',\n        'θ': '8', 'ι': 'i', 'κ': 'k', 'λ': 'l', 'μ': 'm', 'ν': 'n', 'ξ': '3',\n        'ο': 'o', 'π': 'p', 'ρ': 'r', 'σ': 's', 'τ': 't', 'υ': 'y', 'φ': 'f',\n        'χ': 'x', 'ψ': 'ps', 'ω': 'w', 'ά': 'a', 'έ': 'e', 'ί': 'i', 'ό': 'o',\n        'ύ': 'y', 'ή': 'h', 'ώ': 'w', 'ς': 's', 'ϊ': 'i', 'ΰ': 'y', 'ϋ': 'y',\n        'ΐ': 'i', 'Α': 'A', 'Β': 'B', 'Γ': 'G', 'Δ': 'D', 'Ε': 'E', 'Ζ': 'Z',\n        'Η': 'H', 'Θ': '8', 'Ι': 'I', 'Κ': 'K', 'Λ': 'L', 'Μ': 'M', 'Ν': 'N',\n        'Ξ': '3', 'Ο': 'O', 'Π': 'P', 'Ρ': 'R', 'Σ': 'S', 'Τ': 'T', 'Υ': 'Y',\n        'Φ': 'F', 'Χ': 'X', 'Ψ': 'PS', 'Ω': 'W', 'Ά': 'A', 'Έ': 'E', 'Ί': 'I',\n        'Ό': 'O', 'Ύ': 'Y', 'Ή': 'H', 'Ώ': 'W', 'Ϊ': 'I', 'Ϋ': 'Y'\n    };\n    var TURKISH_MAP = {\n        'ş': 's', 'Ş': 'S', 'ı': 'i', 'İ': 'I', 'ç': 'c', 'Ç': 'C', 'ü': 'u',\n        'Ü': 'U', 'ö': 'o', 'Ö': 'O', 'ğ': 'g', 'Ğ': 'G'\n    };\n    var ROMANIAN_MAP = {\n        'ă': 'a', 'î': 'i', 'ș': 's', 'ț': 't', 'â': 'a',\n        'Ă': 'A', 'Î': 'I', 'Ș': 'S', 'Ț': 'T', 'Â': 'A'\n    };\n    var RUSSIAN_MAP = {\n        'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd', 'е': 'e', 'ё': 'yo',\n        'ж': 'zh', 'з': 'z', 'и': 'i', 'й': 'j', 'к': 'k', 'л': 'l', 'м': 'm',\n        'н': 'n', 'о': 'o', 'п': 'p', 'р': 'r', 'с': 's', 'т': 't', 'у': 'u',\n        'ф': 'f', 'х': 'h', 'ц': 'c', 'ч': 'ch', 'ш': 'sh', 'щ': 'sh', 'ъ': '',\n        'ы': 'y', 'ь': '', 'э': 'e', 'ю': 'yu', 'я': 'ya',\n        'А': 'A', 'Б': 'B', 'В': 'V', 'Г': 'G', 'Д': 'D', 'Е': 'E', 'Ё': 'Yo',\n        'Ж': 'Zh', 'З': 'Z', 'И': 'I', 'Й': 'J', 'К': 'K', 'Л': 'L', 'М': 'M',\n        'Н': 'N', 'О': 'O', 'П': 'P', 'Р': 'R', 'С': 'S', 'Т': 'T', 'У': 'U',\n        'Ф': 'F', 'Х': 'H', 'Ц': 'C', 'Ч': 'Ch', 'Ш': 'Sh', 'Щ': 'Sh', 'Ъ': '',\n        'Ы': 'Y', 'Ь': '', 'Э': 'E', 'Ю': 'Yu', 'Я': 'Ya'\n    };\n    var UKRAINIAN_MAP = {\n        'Є': 'Ye', 'І': 'I', 'Ї': 'Yi', 'Ґ': 'G', 'є': 'ye', 'і': 'i',\n        'ї': 'yi', 'ґ': 'g'\n    };\n    var CZECH_MAP = {\n        'č': 'c', 'ď': 'd', 'ě': 'e', 'ň': 'n', 'ř': 'r', 'š': 's', 'ť': 't',\n        'ů': 'u', 'ž': 'z', 'Č': 'C', 'Ď': 'D', 'Ě': 'E', 'Ň': 'N', 'Ř': 'R',\n        'Š': 'S', 'Ť': 'T', 'Ů': 'U', 'Ž': 'Z'\n    };\n    var POLISH_MAP = {\n        'ą': 'a', 'ć': 'c', 'ę': 'e', 'ł': 'l', 'ń': 'n', 'ó': 'o', 'ś': 's',\n        'ź': 'z', 'ż': 'z',\n        'Ą': 'A', 'Ć': 'C', 'Ę': 'E', 'Ł': 'L', 'Ń': 'N', 'Ó': 'O', 'Ś': 'S',\n        'Ź': 'Z', 'Ż': 'Z'\n    };\n    var LATVIAN_MAP = {\n        'ā': 'a', 'č': 'c', 'ē': 'e', 'ģ': 'g', 'ī': 'i', 'ķ': 'k', 'ļ': 'l',\n        'ņ': 'n', 'š': 's', 'ū': 'u', 'ž': 'z',\n        'Ā': 'A', 'Č': 'C', 'Ē': 'E', 'Ģ': 'G', 'Ī': 'I', 'Ķ': 'K', 'Ļ': 'L',\n        'Ņ': 'N', 'Š': 'S', 'Ū': 'U', 'Ž': 'Z'\n    };\n    var ARABIC_MAP = {\n        'أ': 'a', 'ب': 'b', 'ت': 't', 'ث': 'th', 'ج': 'g', 'ح': 'h', 'خ': 'kh', 'د': 'd',\n        'ذ': 'th', 'ر': 'r', 'ز': 'z', 'س': 's', 'ش': 'sh', 'ص': 's', 'ض': 'd', 'ط': 't',\n        'ظ': 'th', 'ع': 'aa', 'غ': 'gh', 'ف': 'f', 'ق': 'k', 'ك': 'k', 'ل': 'l', 'م': 'm',\n        'ن': 'n', 'ه': 'h', 'و': 'o', 'ي': 'y'\n    };\n    var LITHUANIAN_MAP = {\n        'ą': 'a', 'č': 'c', 'ę': 'e', 'ė': 'e', 'į': 'i', 'š': 's', 'ų': 'u',\n        'ū': 'u', 'ž': 'z',\n        'Ą': 'A', 'Č': 'C', 'Ę': 'E', 'Ė': 'E', 'Į': 'I', 'Š': 'S', 'Ų': 'U',\n        'Ū': 'U', 'Ž': 'Z'\n    };\n    var SERBIAN_MAP = {\n        'ђ': 'dj', 'ј': 'j', 'љ': 'lj', 'њ': 'nj', 'ћ': 'c', 'џ': 'dz',\n        'đ': 'dj', 'Ђ': 'Dj', 'Ј': 'j', 'Љ': 'Lj', 'Њ': 'Nj', 'Ћ': 'C',\n        'Џ': 'Dz', 'Đ': 'Dj'\n    };\n    var AZERBAIJANI_MAP = {\n        'ç': 'c', 'ə': 'e', 'ğ': 'g', 'ı': 'i', 'ö': 'o', 'ş': 's', 'ü': 'u',\n        'Ç': 'C', 'Ə': 'E', 'Ğ': 'G', 'İ': 'I', 'Ö': 'O', 'Ş': 'S', 'Ü': 'U'\n    };\n    var GEORGIAN_MAP = {\n        'ა': 'a', 'ბ': 'b', 'გ': 'g', 'დ': 'd', 'ე': 'e', 'ვ': 'v', 'ზ': 'z',\n        'თ': 't', 'ი': 'i', 'კ': 'k', 'ლ': 'l', 'მ': 'm', 'ნ': 'n', 'ო': 'o',\n        'პ': 'p', 'ჟ': 'j', 'რ': 'r', 'ს': 's', 'ტ': 't', 'უ': 'u', 'ფ': 'f',\n        'ქ': 'q', 'ღ': 'g', 'ყ': 'y', 'შ': 'sh', 'ჩ': 'ch', 'ც': 'c', 'ძ': 'dz',\n        'წ': 'w', 'ჭ': 'ch', 'ხ': 'x', 'ჯ': 'j', 'ჰ': 'h'\n    };\n\n    var ALL_DOWNCODE_MAPS = [\n        LATIN_MAP,\n        LATIN_SYMBOLS_MAP,\n        GREEK_MAP,\n        TURKISH_MAP,\n        ROMANIAN_MAP,\n        RUSSIAN_MAP,\n        UKRAINIAN_MAP,\n        CZECH_MAP,\n        POLISH_MAP,\n        LATVIAN_MAP,\n        ARABIC_MAP,\n        LITHUANIAN_MAP,\n        SERBIAN_MAP,\n        AZERBAIJANI_MAP,\n        GEORGIAN_MAP\n    ];\n\n    var Downcoder = {\n        'Initialize': function() {\n            if (Downcoder.map) {  // already made\n                return;\n            }\n            Downcoder.map = {};\n            Downcoder.chars = [];\n            for (var i = 0; i < ALL_DOWNCODE_MAPS.length; i++) {\n                var lookup = ALL_DOWNCODE_MAPS[i];\n                for (var c in lookup) {\n                    if (lookup.hasOwnProperty(c)) {\n                        Downcoder.map[c] = lookup[c];\n                    }\n                }\n            }\n            for (var k in Downcoder.map) {\n                if (Downcoder.map.hasOwnProperty(k)) {\n                    Downcoder.chars.push(k);\n                }\n            }\n            Downcoder.regex = new RegExp(Downcoder.chars.join('|'), 'g');\n        }\n    };\n\n    function downcode(slug) {\n        Downcoder.Initialize();\n        return slug.replace(Downcoder.regex, function(m) {\n            return Downcoder.map[m];\n        });\n    }\n\n\n    function URLify(s, num_chars, allowUnicode) {\n        // changes, e.g., \"Petty theft\" to \"petty-theft\"\n        // remove all these words from the string before urlifying\n        if (!allowUnicode) {\n            s = downcode(s);\n        }\n        var removelist = [\n            \"a\", \"an\", \"as\", \"at\", \"before\", \"but\", \"by\", \"for\", \"from\", \"is\",\n            \"in\", \"into\", \"like\", \"of\", \"off\", \"on\", \"onto\", \"per\", \"since\",\n            \"than\", \"the\", \"this\", \"that\", \"to\", \"up\", \"via\", \"with\"\n        ];\n        var r = new RegExp('\\\\b(' + removelist.join('|') + ')\\\\b', 'gi');\n        s = s.replace(r, '');\n        // if downcode doesn't hit, the char will be stripped here\n        if (allowUnicode) {\n            // Keep Unicode letters including both lowercase and uppercase\n            // characters, whitespace, and dash; remove other characters.\n            s = XRegExp.replace(s, XRegExp('[^-_\\\\p{L}\\\\p{N}\\\\s]', 'g'), '');\n        } else {\n            s = s.replace(/[^-\\w\\s]/g, '');  // remove unneeded chars\n        }\n        s = s.replace(/^\\s+|\\s+$/g, '');   // trim leading/trailing spaces\n        s = s.replace(/[-\\s]+/g, '-');     // convert spaces to hyphens\n        s = s.toLowerCase();               // convert to lowercase\n        return s.substring(0, num_chars);  // trim to first num_chars chars\n    }\n    window.URLify = URLify;\n})();\n"
  },
  {
    "path": "static_cdn/static_root/admin/js/vendor/jquery/LICENSE-JQUERY.txt",
    "content": "Copyright jQuery Foundation and other contributors, https://jquery.org/\n\nThis software consists of voluntary contributions made by many\nindividuals. For exact contribution history, see the revision history\navailable at https://github.com/jquery/jquery\n\n====\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "static_cdn/static_root/admin/js/vendor/jquery/jquery.js",
    "content": "/*!\n * jQuery JavaScript Library v2.2.3\n * http://jquery.com/\n *\n * Includes Sizzle.js\n * http://sizzlejs.com/\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license\n * http://jquery.org/license\n *\n * Date: 2016-04-05T19:26Z\n */\n\n(function( global, factory ) {\n\n\tif ( typeof module === \"object\" && typeof module.exports === \"object\" ) {\n\t\t// For CommonJS and CommonJS-like environments where a proper `window`\n\t\t// is present, execute the factory and get jQuery.\n\t\t// For environments that do not have a `window` with a `document`\n\t\t// (such as Node.js), expose a factory as module.exports.\n\t\t// This accentuates the need for the creation of a real `window`.\n\t\t// e.g. var jQuery = require(\"jquery\")(window);\n\t\t// See ticket #14549 for more info.\n\t\tmodule.exports = global.document ?\n\t\t\tfactory( global, true ) :\n\t\t\tfunction( w ) {\n\t\t\t\tif ( !w.document ) {\n\t\t\t\t\tthrow new Error( \"jQuery requires a window with a document\" );\n\t\t\t\t}\n\t\t\t\treturn factory( w );\n\t\t\t};\n\t} else {\n\t\tfactory( global );\n\t}\n\n// Pass this if window is not defined yet\n}(typeof window !== \"undefined\" ? window : this, function( window, noGlobal ) {\n\n// Support: Firefox 18+\n// Can't be in strict mode, several libs including ASP.NET trace\n// the stack via arguments.caller.callee and Firefox dies if\n// you try to trace through \"use strict\" call chains. (#13335)\n//\"use strict\";\nvar arr = [];\n\nvar document = window.document;\n\nvar slice = arr.slice;\n\nvar concat = arr.concat;\n\nvar push = arr.push;\n\nvar indexOf = arr.indexOf;\n\nvar class2type = {};\n\nvar toString = class2type.toString;\n\nvar hasOwn = class2type.hasOwnProperty;\n\nvar support = {};\n\n\n\nvar\n\tversion = \"2.2.3\",\n\n\t// Define a local copy of jQuery\n\tjQuery = function( selector, context ) {\n\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\t// Need init if jQuery is called (just allow error to be thrown if not included)\n\t\treturn new jQuery.fn.init( selector, context );\n\t},\n\n\t// Support: Android<4.1\n\t// Make sure we trim BOM and NBSP\n\trtrim = /^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g,\n\n\t// Matches dashed string for camelizing\n\trmsPrefix = /^-ms-/,\n\trdashAlpha = /-([\\da-z])/gi,\n\n\t// Used by jQuery.camelCase as callback to replace()\n\tfcamelCase = function( all, letter ) {\n\t\treturn letter.toUpperCase();\n\t};\n\njQuery.fn = jQuery.prototype = {\n\n\t// The current version of jQuery being used\n\tjquery: version,\n\n\tconstructor: jQuery,\n\n\t// Start with an empty selector\n\tselector: \"\",\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\ttoArray: function() {\n\t\treturn slice.call( this );\n\t},\n\n\t// Get the Nth element in the matched element set OR\n\t// Get the whole matched element set as a clean array\n\tget: function( num ) {\n\t\treturn num != null ?\n\n\t\t\t// Return just the one element from the set\n\t\t\t( num < 0 ? this[ num + this.length ] : this[ num ] ) :\n\n\t\t\t// Return all the elements in a clean array\n\t\t\tslice.call( this );\n\t},\n\n\t// Take an array of elements and push it onto the stack\n\t// (returning the new matched element set)\n\tpushStack: function( elems ) {\n\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = jQuery.merge( this.constructor(), elems );\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\n\t\tret.context = this.context;\n\n\t\t// Return the newly-formed element set\n\t\treturn ret;\n\t},\n\n\t// Execute a callback for every element in the matched set.\n\teach: function( callback ) {\n\t\treturn jQuery.each( this, callback );\n\t},\n\n\tmap: function( callback ) {\n\t\treturn this.pushStack( jQuery.map( this, function( elem, i ) {\n\t\t\treturn callback.call( elem, i, elem );\n\t\t} ) );\n\t},\n\n\tslice: function() {\n\t\treturn this.pushStack( slice.apply( this, arguments ) );\n\t},\n\n\tfirst: function() {\n\t\treturn this.eq( 0 );\n\t},\n\n\tlast: function() {\n\t\treturn this.eq( -1 );\n\t},\n\n\teq: function( i ) {\n\t\tvar len = this.length,\n\t\t\tj = +i + ( i < 0 ? len : 0 );\n\t\treturn this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );\n\t},\n\n\tend: function() {\n\t\treturn this.prevObject || this.constructor();\n\t},\n\n\t// For internal use only.\n\t// Behaves like an Array's method, not like a jQuery method.\n\tpush: push,\n\tsort: arr.sort,\n\tsplice: arr.splice\n};\n\njQuery.extend = jQuery.fn.extend = function() {\n\tvar options, name, src, copy, copyIsArray, clone,\n\t\ttarget = arguments[ 0 ] || {},\n\t\ti = 1,\n\t\tlength = arguments.length,\n\t\tdeep = false;\n\n\t// Handle a deep copy situation\n\tif ( typeof target === \"boolean\" ) {\n\t\tdeep = target;\n\n\t\t// Skip the boolean and the target\n\t\ttarget = arguments[ i ] || {};\n\t\ti++;\n\t}\n\n\t// Handle case when target is a string or something (possible in deep copy)\n\tif ( typeof target !== \"object\" && !jQuery.isFunction( target ) ) {\n\t\ttarget = {};\n\t}\n\n\t// Extend jQuery itself if only one argument is passed\n\tif ( i === length ) {\n\t\ttarget = this;\n\t\ti--;\n\t}\n\n\tfor ( ; i < length; i++ ) {\n\n\t\t// Only deal with non-null/undefined values\n\t\tif ( ( options = arguments[ i ] ) != null ) {\n\n\t\t\t// Extend the base object\n\t\t\tfor ( name in options ) {\n\t\t\t\tsrc = target[ name ];\n\t\t\t\tcopy = options[ name ];\n\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif ( target === copy ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Recurse if we're merging plain objects or arrays\n\t\t\t\tif ( deep && copy && ( jQuery.isPlainObject( copy ) ||\n\t\t\t\t\t( copyIsArray = jQuery.isArray( copy ) ) ) ) {\n\n\t\t\t\t\tif ( copyIsArray ) {\n\t\t\t\t\t\tcopyIsArray = false;\n\t\t\t\t\t\tclone = src && jQuery.isArray( src ) ? src : [];\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclone = src && jQuery.isPlainObject( src ) ? src : {};\n\t\t\t\t\t}\n\n\t\t\t\t\t// Never move original objects, clone them\n\t\t\t\t\ttarget[ name ] = jQuery.extend( deep, clone, copy );\n\n\t\t\t\t// Don't bring in undefined values\n\t\t\t\t} else if ( copy !== undefined ) {\n\t\t\t\t\ttarget[ name ] = copy;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the modified object\n\treturn target;\n};\n\njQuery.extend( {\n\n\t// Unique for each copy of jQuery on the page\n\texpando: \"jQuery\" + ( version + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// Assume jQuery is ready without the ready module\n\tisReady: true,\n\n\terror: function( msg ) {\n\t\tthrow new Error( msg );\n\t},\n\n\tnoop: function() {},\n\n\tisFunction: function( obj ) {\n\t\treturn jQuery.type( obj ) === \"function\";\n\t},\n\n\tisArray: Array.isArray,\n\n\tisWindow: function( obj ) {\n\t\treturn obj != null && obj === obj.window;\n\t},\n\n\tisNumeric: function( obj ) {\n\n\t\t// parseFloat NaNs numeric-cast false positives (null|true|false|\"\")\n\t\t// ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n\t\t// subtraction forces infinities to NaN\n\t\t// adding 1 corrects loss of precision from parseFloat (#15100)\n\t\tvar realStringObj = obj && obj.toString();\n\t\treturn !jQuery.isArray( obj ) && ( realStringObj - parseFloat( realStringObj ) + 1 ) >= 0;\n\t},\n\n\tisPlainObject: function( obj ) {\n\t\tvar key;\n\n\t\t// Not plain objects:\n\t\t// - Any object or value whose internal [[Class]] property is not \"[object Object]\"\n\t\t// - DOM nodes\n\t\t// - window\n\t\tif ( jQuery.type( obj ) !== \"object\" || obj.nodeType || jQuery.isWindow( obj ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Not own constructor property must be Object\n\t\tif ( obj.constructor &&\n\t\t\t\t!hasOwn.call( obj, \"constructor\" ) &&\n\t\t\t\t!hasOwn.call( obj.constructor.prototype || {}, \"isPrototypeOf\" ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Own properties are enumerated firstly, so to speed up,\n\t\t// if last one is own, then all properties are own\n\t\tfor ( key in obj ) {}\n\n\t\treturn key === undefined || hasOwn.call( obj, key );\n\t},\n\n\tisEmptyObject: function( obj ) {\n\t\tvar name;\n\t\tfor ( name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\ttype: function( obj ) {\n\t\tif ( obj == null ) {\n\t\t\treturn obj + \"\";\n\t\t}\n\n\t\t// Support: Android<4.0, iOS<6 (functionish RegExp)\n\t\treturn typeof obj === \"object\" || typeof obj === \"function\" ?\n\t\t\tclass2type[ toString.call( obj ) ] || \"object\" :\n\t\t\ttypeof obj;\n\t},\n\n\t// Evaluates a script in a global context\n\tglobalEval: function( code ) {\n\t\tvar script,\n\t\t\tindirect = eval;\n\n\t\tcode = jQuery.trim( code );\n\n\t\tif ( code ) {\n\n\t\t\t// If the code includes a valid, prologue position\n\t\t\t// strict mode pragma, execute code by injecting a\n\t\t\t// script tag into the document.\n\t\t\tif ( code.indexOf( \"use strict\" ) === 1 ) {\n\t\t\t\tscript = document.createElement( \"script\" );\n\t\t\t\tscript.text = code;\n\t\t\t\tdocument.head.appendChild( script ).parentNode.removeChild( script );\n\t\t\t} else {\n\n\t\t\t\t// Otherwise, avoid the DOM node creation, insertion\n\t\t\t\t// and removal by using an indirect global eval\n\n\t\t\t\tindirect( code );\n\t\t\t}\n\t\t}\n\t},\n\n\t// Convert dashed to camelCase; used by the css and data modules\n\t// Support: IE9-11+\n\t// Microsoft forgot to hump their vendor prefix (#9572)\n\tcamelCase: function( string ) {\n\t\treturn string.replace( rmsPrefix, \"ms-\" ).replace( rdashAlpha, fcamelCase );\n\t},\n\n\tnodeName: function( elem, name ) {\n\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();\n\t},\n\n\teach: function( obj, callback ) {\n\t\tvar length, i = 0;\n\n\t\tif ( isArrayLike( obj ) ) {\n\t\t\tlength = obj.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfor ( i in obj ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn obj;\n\t},\n\n\t// Support: Android<4.1\n\ttrim: function( text ) {\n\t\treturn text == null ?\n\t\t\t\"\" :\n\t\t\t( text + \"\" ).replace( rtrim, \"\" );\n\t},\n\n\t// results is for internal usage only\n\tmakeArray: function( arr, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( arr != null ) {\n\t\t\tif ( isArrayLike( Object( arr ) ) ) {\n\t\t\t\tjQuery.merge( ret,\n\t\t\t\t\ttypeof arr === \"string\" ?\n\t\t\t\t\t[ arr ] : arr\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tpush.call( ret, arr );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, arr, i ) {\n\t\treturn arr == null ? -1 : indexOf.call( arr, elem, i );\n\t},\n\n\tmerge: function( first, second ) {\n\t\tvar len = +second.length,\n\t\t\tj = 0,\n\t\t\ti = first.length;\n\n\t\tfor ( ; j < len; j++ ) {\n\t\t\tfirst[ i++ ] = second[ j ];\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, invert ) {\n\t\tvar callbackInverse,\n\t\t\tmatches = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tcallbackExpect = !invert;\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( ; i < length; i++ ) {\n\t\t\tcallbackInverse = !callback( elems[ i ], i );\n\t\t\tif ( callbackInverse !== callbackExpect ) {\n\t\t\t\tmatches.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn matches;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar length, value,\n\t\t\ti = 0,\n\t\t\tret = [];\n\n\t\t// Go through the array, translating each of the items to their new values\n\t\tif ( isArrayLike( elems ) ) {\n\t\t\tlength = elems.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Go through every key on the object,\n\t\t} else {\n\t\t\tfor ( i in elems ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn concat.apply( [], ret );\n\t},\n\n\t// A global GUID counter for objects\n\tguid: 1,\n\n\t// Bind a function to a context, optionally partially applying any\n\t// arguments.\n\tproxy: function( fn, context ) {\n\t\tvar tmp, args, proxy;\n\n\t\tif ( typeof context === \"string\" ) {\n\t\t\ttmp = fn[ context ];\n\t\t\tcontext = fn;\n\t\t\tfn = tmp;\n\t\t}\n\n\t\t// Quick check to determine if target is callable, in the spec\n\t\t// this throws a TypeError, but we will just return undefined.\n\t\tif ( !jQuery.isFunction( fn ) ) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// Simulated bind\n\t\targs = slice.call( arguments, 2 );\n\t\tproxy = function() {\n\t\t\treturn fn.apply( context || this, args.concat( slice.call( arguments ) ) );\n\t\t};\n\n\t\t// Set the guid of unique handler to the same of original handler, so it can be removed\n\t\tproxy.guid = fn.guid = fn.guid || jQuery.guid++;\n\n\t\treturn proxy;\n\t},\n\n\tnow: Date.now,\n\n\t// jQuery.support is not used in Core but other projects attach their\n\t// properties to it so it needs to exist.\n\tsupport: support\n} );\n\n// JSHint would error on this code due to the Symbol not being defined in ES5.\n// Defining this global in .jshintrc would create a danger of using the global\n// unguarded in another place, it seems safer to just disable JSHint for these\n// three lines.\n/* jshint ignore: start */\nif ( typeof Symbol === \"function\" ) {\n\tjQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];\n}\n/* jshint ignore: end */\n\n// Populate the class2type map\njQuery.each( \"Boolean Number String Function Array Date RegExp Object Error Symbol\".split( \" \" ),\nfunction( i, name ) {\n\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n} );\n\nfunction isArrayLike( obj ) {\n\n\t// Support: iOS 8.2 (not reproducible in simulator)\n\t// `in` check used to prevent JIT error (gh-2145)\n\t// hasOwn isn't used here due to false negatives\n\t// regarding Nodelist length in IE\n\tvar length = !!obj && \"length\" in obj && obj.length,\n\t\ttype = jQuery.type( obj );\n\n\tif ( type === \"function\" || jQuery.isWindow( obj ) ) {\n\t\treturn false;\n\t}\n\n\treturn type === \"array\" || length === 0 ||\n\t\ttypeof length === \"number\" && length > 0 && ( length - 1 ) in obj;\n}\nvar Sizzle =\n/*!\n * Sizzle CSS Selector Engine v2.2.1\n * http://sizzlejs.com/\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license\n * http://jquery.org/license\n *\n * Date: 2015-10-17\n */\n(function( window ) {\n\nvar i,\n\tsupport,\n\tExpr,\n\tgetText,\n\tisXML,\n\ttokenize,\n\tcompile,\n\tselect,\n\toutermostContext,\n\tsortInput,\n\thasDuplicate,\n\n\t// Local document vars\n\tsetDocument,\n\tdocument,\n\tdocElem,\n\tdocumentIsHTML,\n\trbuggyQSA,\n\trbuggyMatches,\n\tmatches,\n\tcontains,\n\n\t// Instance-specific data\n\texpando = \"sizzle\" + 1 * new Date(),\n\tpreferredDoc = window.document,\n\tdirruns = 0,\n\tdone = 0,\n\tclassCache = createCache(),\n\ttokenCache = createCache(),\n\tcompilerCache = createCache(),\n\tsortOrder = function( a, b ) {\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t}\n\t\treturn 0;\n\t},\n\n\t// General-purpose constants\n\tMAX_NEGATIVE = 1 << 31,\n\n\t// Instance methods\n\thasOwn = ({}).hasOwnProperty,\n\tarr = [],\n\tpop = arr.pop,\n\tpush_native = arr.push,\n\tpush = arr.push,\n\tslice = arr.slice,\n\t// Use a stripped-down indexOf as it's faster than native\n\t// http://jsperf.com/thor-indexof-vs-for/5\n\tindexOf = function( list, elem ) {\n\t\tvar i = 0,\n\t\t\tlen = list.length;\n\t\tfor ( ; i < len; i++ ) {\n\t\t\tif ( list[i] === elem ) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t},\n\n\tbooleans = \"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",\n\n\t// Regular expressions\n\n\t// http://www.w3.org/TR/css3-selectors/#whitespace\n\twhitespace = \"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",\n\n\t// http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier\n\tidentifier = \"(?:\\\\\\\\.|[\\\\w-]|[^\\\\x00-\\\\xa0])+\",\n\n\t// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors\n\tattributes = \"\\\\[\" + whitespace + \"*(\" + identifier + \")(?:\" + whitespace +\n\t\t// Operator (capture 2)\n\t\t\"*([*^$|!~]?=)\" + whitespace +\n\t\t// \"Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]\"\n\t\t\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\" + identifier + \"))|)\" + whitespace +\n\t\t\"*\\\\]\",\n\n\tpseudos = \":(\" + identifier + \")(?:\\\\((\" +\n\t\t// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:\n\t\t// 1. quoted (capture 3; capture 4 or capture 5)\n\t\t\"('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|\" +\n\t\t// 2. simple (capture 6)\n\t\t\"((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\" + attributes + \")*)|\" +\n\t\t// 3. anything else (capture 2)\n\t\t\".*\" +\n\t\t\")\\\\)|)\",\n\n\t// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter\n\trwhitespace = new RegExp( whitespace + \"+\", \"g\" ),\n\trtrim = new RegExp( \"^\" + whitespace + \"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\" + whitespace + \"+$\", \"g\" ),\n\n\trcomma = new RegExp( \"^\" + whitespace + \"*,\" + whitespace + \"*\" ),\n\trcombinators = new RegExp( \"^\" + whitespace + \"*([>+~]|\" + whitespace + \")\" + whitespace + \"*\" ),\n\n\trattributeQuotes = new RegExp( \"=\" + whitespace + \"*([^\\\\]'\\\"]*?)\" + whitespace + \"*\\\\]\", \"g\" ),\n\n\trpseudo = new RegExp( pseudos ),\n\tridentifier = new RegExp( \"^\" + identifier + \"$\" ),\n\n\tmatchExpr = {\n\t\t\"ID\": new RegExp( \"^#(\" + identifier + \")\" ),\n\t\t\"CLASS\": new RegExp( \"^\\\\.(\" + identifier + \")\" ),\n\t\t\"TAG\": new RegExp( \"^(\" + identifier + \"|[*])\" ),\n\t\t\"ATTR\": new RegExp( \"^\" + attributes ),\n\t\t\"PSEUDO\": new RegExp( \"^\" + pseudos ),\n\t\t\"CHILD\": new RegExp( \"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\" + whitespace +\n\t\t\t\"*(even|odd|(([+-]|)(\\\\d*)n|)\" + whitespace + \"*(?:([+-]|)\" + whitespace +\n\t\t\t\"*(\\\\d+)|))\" + whitespace + \"*\\\\)|)\", \"i\" ),\n\t\t\"bool\": new RegExp( \"^(?:\" + booleans + \")$\", \"i\" ),\n\t\t// For use in libraries implementing .is()\n\t\t// We use this for POS matching in `select`\n\t\t\"needsContext\": new RegExp( \"^\" + whitespace + \"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\" +\n\t\t\twhitespace + \"*((?:-\\\\d)?\\\\d*)\" + whitespace + \"*\\\\)|)(?=[^-]|$)\", \"i\" )\n\t},\n\n\trinputs = /^(?:input|select|textarea|button)$/i,\n\trheader = /^h\\d$/i,\n\n\trnative = /^[^{]+\\{\\s*\\[native \\w/,\n\n\t// Easily-parseable/retrievable ID or TAG or CLASS selectors\n\trquickExpr = /^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,\n\n\trsibling = /[+~]/,\n\trescape = /'|\\\\/g,\n\n\t// CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters\n\trunescape = new RegExp( \"\\\\\\\\([\\\\da-f]{1,6}\" + whitespace + \"?|(\" + whitespace + \")|.)\", \"ig\" ),\n\tfunescape = function( _, escaped, escapedWhitespace ) {\n\t\tvar high = \"0x\" + escaped - 0x10000;\n\t\t// NaN means non-codepoint\n\t\t// Support: Firefox<24\n\t\t// Workaround erroneous numeric interpretation of +\"0x\"\n\t\treturn high !== high || escapedWhitespace ?\n\t\t\tescaped :\n\t\t\thigh < 0 ?\n\t\t\t\t// BMP codepoint\n\t\t\t\tString.fromCharCode( high + 0x10000 ) :\n\t\t\t\t// Supplemental Plane codepoint (surrogate pair)\n\t\t\t\tString.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );\n\t},\n\n\t// Used for iframes\n\t// See setDocument()\n\t// Removing the function wrapper causes a \"Permission Denied\"\n\t// error in IE\n\tunloadHandler = function() {\n\t\tsetDocument();\n\t};\n\n// Optimize for push.apply( _, NodeList )\ntry {\n\tpush.apply(\n\t\t(arr = slice.call( preferredDoc.childNodes )),\n\t\tpreferredDoc.childNodes\n\t);\n\t// Support: Android<4.0\n\t// Detect silently failing push.apply\n\tarr[ preferredDoc.childNodes.length ].nodeType;\n} catch ( e ) {\n\tpush = { apply: arr.length ?\n\n\t\t// Leverage slice if possible\n\t\tfunction( target, els ) {\n\t\t\tpush_native.apply( target, slice.call(els) );\n\t\t} :\n\n\t\t// Support: IE<9\n\t\t// Otherwise append directly\n\t\tfunction( target, els ) {\n\t\t\tvar j = target.length,\n\t\t\t\ti = 0;\n\t\t\t// Can't trust NodeList.length\n\t\t\twhile ( (target[j++] = els[i++]) ) {}\n\t\t\ttarget.length = j - 1;\n\t\t}\n\t};\n}\n\nfunction Sizzle( selector, context, results, seed ) {\n\tvar m, i, elem, nid, nidselect, match, groups, newSelector,\n\t\tnewContext = context && context.ownerDocument,\n\n\t\t// nodeType defaults to 9, since context defaults to document\n\t\tnodeType = context ? context.nodeType : 9;\n\n\tresults = results || [];\n\n\t// Return early from calls with invalid selector or context\n\tif ( typeof selector !== \"string\" || !selector ||\n\t\tnodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {\n\n\t\treturn results;\n\t}\n\n\t// Try to shortcut find operations (as opposed to filters) in HTML documents\n\tif ( !seed ) {\n\n\t\tif ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {\n\t\t\tsetDocument( context );\n\t\t}\n\t\tcontext = context || document;\n\n\t\tif ( documentIsHTML ) {\n\n\t\t\t// If the selector is sufficiently simple, try using a \"get*By*\" DOM method\n\t\t\t// (excepting DocumentFragment context, where the methods don't exist)\n\t\t\tif ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {\n\n\t\t\t\t// ID selector\n\t\t\t\tif ( (m = match[1]) ) {\n\n\t\t\t\t\t// Document context\n\t\t\t\t\tif ( nodeType === 9 ) {\n\t\t\t\t\t\tif ( (elem = context.getElementById( m )) ) {\n\n\t\t\t\t\t\t\t// Support: IE, Opera, Webkit\n\t\t\t\t\t\t\t// TODO: identify versions\n\t\t\t\t\t\t\t// getElementById can match elements by name instead of ID\n\t\t\t\t\t\t\tif ( elem.id === m ) {\n\t\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t// Element context\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// Support: IE, Opera, Webkit\n\t\t\t\t\t\t// TODO: identify versions\n\t\t\t\t\t\t// getElementById can match elements by name instead of ID\n\t\t\t\t\t\tif ( newContext && (elem = newContext.getElementById( m )) &&\n\t\t\t\t\t\t\tcontains( context, elem ) &&\n\t\t\t\t\t\t\telem.id === m ) {\n\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t// Type selector\n\t\t\t\t} else if ( match[2] ) {\n\t\t\t\t\tpush.apply( results, context.getElementsByTagName( selector ) );\n\t\t\t\t\treturn results;\n\n\t\t\t\t// Class selector\n\t\t\t\t} else if ( (m = match[3]) && support.getElementsByClassName &&\n\t\t\t\t\tcontext.getElementsByClassName ) {\n\n\t\t\t\t\tpush.apply( results, context.getElementsByClassName( m ) );\n\t\t\t\t\treturn results;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Take advantage of querySelectorAll\n\t\t\tif ( support.qsa &&\n\t\t\t\t!compilerCache[ selector + \" \" ] &&\n\t\t\t\t(!rbuggyQSA || !rbuggyQSA.test( selector )) ) {\n\n\t\t\t\tif ( nodeType !== 1 ) {\n\t\t\t\t\tnewContext = context;\n\t\t\t\t\tnewSelector = selector;\n\n\t\t\t\t// qSA looks outside Element context, which is not what we want\n\t\t\t\t// Thanks to Andrew Dupont for this workaround technique\n\t\t\t\t// Support: IE <=8\n\t\t\t\t// Exclude object elements\n\t\t\t\t} else if ( context.nodeName.toLowerCase() !== \"object\" ) {\n\n\t\t\t\t\t// Capture the context ID, setting it first if necessary\n\t\t\t\t\tif ( (nid = context.getAttribute( \"id\" )) ) {\n\t\t\t\t\t\tnid = nid.replace( rescape, \"\\\\$&\" );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcontext.setAttribute( \"id\", (nid = expando) );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prefix every selector in the list\n\t\t\t\t\tgroups = tokenize( selector );\n\t\t\t\t\ti = groups.length;\n\t\t\t\t\tnidselect = ridentifier.test( nid ) ? \"#\" + nid : \"[id='\" + nid + \"']\";\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tgroups[i] = nidselect + \" \" + toSelector( groups[i] );\n\t\t\t\t\t}\n\t\t\t\t\tnewSelector = groups.join( \",\" );\n\n\t\t\t\t\t// Expand context for sibling selectors\n\t\t\t\t\tnewContext = rsibling.test( selector ) && testContext( context.parentNode ) ||\n\t\t\t\t\t\tcontext;\n\t\t\t\t}\n\n\t\t\t\tif ( newSelector ) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tpush.apply( results,\n\t\t\t\t\t\t\tnewContext.querySelectorAll( newSelector )\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t} catch ( qsaError ) {\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tif ( nid === expando ) {\n\t\t\t\t\t\t\tcontext.removeAttribute( \"id\" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// All others\n\treturn select( selector.replace( rtrim, \"$1\" ), context, results, seed );\n}\n\n/**\n * Create key-value caches of limited size\n * @returns {function(string, object)} Returns the Object data after storing it on itself with\n *\tproperty name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)\n *\tdeleting the oldest entry\n */\nfunction createCache() {\n\tvar keys = [];\n\n\tfunction cache( key, value ) {\n\t\t// Use (key + \" \") to avoid collision with native prototype properties (see Issue #157)\n\t\tif ( keys.push( key + \" \" ) > Expr.cacheLength ) {\n\t\t\t// Only keep the most recent entries\n\t\t\tdelete cache[ keys.shift() ];\n\t\t}\n\t\treturn (cache[ key + \" \" ] = value);\n\t}\n\treturn cache;\n}\n\n/**\n * Mark a function for special use by Sizzle\n * @param {Function} fn The function to mark\n */\nfunction markFunction( fn ) {\n\tfn[ expando ] = true;\n\treturn fn;\n}\n\n/**\n * Support testing using an element\n * @param {Function} fn Passed the created div and expects a boolean result\n */\nfunction assert( fn ) {\n\tvar div = document.createElement(\"div\");\n\n\ttry {\n\t\treturn !!fn( div );\n\t} catch (e) {\n\t\treturn false;\n\t} finally {\n\t\t// Remove from its parent by default\n\t\tif ( div.parentNode ) {\n\t\t\tdiv.parentNode.removeChild( div );\n\t\t}\n\t\t// release memory in IE\n\t\tdiv = null;\n\t}\n}\n\n/**\n * Adds the same handler for all of the specified attrs\n * @param {String} attrs Pipe-separated list of attributes\n * @param {Function} handler The method that will be applied\n */\nfunction addHandle( attrs, handler ) {\n\tvar arr = attrs.split(\"|\"),\n\t\ti = arr.length;\n\n\twhile ( i-- ) {\n\t\tExpr.attrHandle[ arr[i] ] = handler;\n\t}\n}\n\n/**\n * Checks document order of two siblings\n * @param {Element} a\n * @param {Element} b\n * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b\n */\nfunction siblingCheck( a, b ) {\n\tvar cur = b && a,\n\t\tdiff = cur && a.nodeType === 1 && b.nodeType === 1 &&\n\t\t\t( ~b.sourceIndex || MAX_NEGATIVE ) -\n\t\t\t( ~a.sourceIndex || MAX_NEGATIVE );\n\n\t// Use IE sourceIndex if available on both nodes\n\tif ( diff ) {\n\t\treturn diff;\n\t}\n\n\t// Check if b follows a\n\tif ( cur ) {\n\t\twhile ( (cur = cur.nextSibling) ) {\n\t\t\tif ( cur === b ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn a ? 1 : -1;\n}\n\n/**\n * Returns a function to use in pseudos for input types\n * @param {String} type\n */\nfunction createInputPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn name === \"input\" && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for buttons\n * @param {String} type\n */\nfunction createButtonPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn (name === \"input\" || name === \"button\") && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for positionals\n * @param {Function} fn\n */\nfunction createPositionalPseudo( fn ) {\n\treturn markFunction(function( argument ) {\n\t\targument = +argument;\n\t\treturn markFunction(function( seed, matches ) {\n\t\t\tvar j,\n\t\t\t\tmatchIndexes = fn( [], seed.length, argument ),\n\t\t\t\ti = matchIndexes.length;\n\n\t\t\t// Match elements found at the specified indexes\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( seed[ (j = matchIndexes[i]) ] ) {\n\t\t\t\t\tseed[j] = !(matches[j] = seed[j]);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t});\n}\n\n/**\n * Checks a node for validity as a Sizzle context\n * @param {Element|Object=} context\n * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value\n */\nfunction testContext( context ) {\n\treturn context && typeof context.getElementsByTagName !== \"undefined\" && context;\n}\n\n// Expose support vars for convenience\nsupport = Sizzle.support = {};\n\n/**\n * Detects XML nodes\n * @param {Element|Object} elem An element or a document\n * @returns {Boolean} True iff elem is a non-HTML XML node\n */\nisXML = Sizzle.isXML = function( elem ) {\n\t// documentElement is verified for cases where it doesn't yet exist\n\t// (such as loading iframes in IE - #4833)\n\tvar documentElement = elem && (elem.ownerDocument || elem).documentElement;\n\treturn documentElement ? documentElement.nodeName !== \"HTML\" : false;\n};\n\n/**\n * Sets document-related variables once based on the current document\n * @param {Element|Object} [doc] An element or document object to use to set the document\n * @returns {Object} Returns the current document\n */\nsetDocument = Sizzle.setDocument = function( node ) {\n\tvar hasCompare, parent,\n\t\tdoc = node ? node.ownerDocument || node : preferredDoc;\n\n\t// Return early if doc is invalid or already selected\n\tif ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {\n\t\treturn document;\n\t}\n\n\t// Update global variables\n\tdocument = doc;\n\tdocElem = document.documentElement;\n\tdocumentIsHTML = !isXML( document );\n\n\t// Support: IE 9-11, Edge\n\t// Accessing iframe documents after unload throws \"permission denied\" errors (jQuery #13936)\n\tif ( (parent = document.defaultView) && parent.top !== parent ) {\n\t\t// Support: IE 11\n\t\tif ( parent.addEventListener ) {\n\t\t\tparent.addEventListener( \"unload\", unloadHandler, false );\n\n\t\t// Support: IE 9 - 10 only\n\t\t} else if ( parent.attachEvent ) {\n\t\t\tparent.attachEvent( \"onunload\", unloadHandler );\n\t\t}\n\t}\n\n\t/* Attributes\n\t---------------------------------------------------------------------- */\n\n\t// Support: IE<8\n\t// Verify that getAttribute really returns attributes and not properties\n\t// (excepting IE8 booleans)\n\tsupport.attributes = assert(function( div ) {\n\t\tdiv.className = \"i\";\n\t\treturn !div.getAttribute(\"className\");\n\t});\n\n\t/* getElement(s)By*\n\t---------------------------------------------------------------------- */\n\n\t// Check if getElementsByTagName(\"*\") returns only elements\n\tsupport.getElementsByTagName = assert(function( div ) {\n\t\tdiv.appendChild( document.createComment(\"\") );\n\t\treturn !div.getElementsByTagName(\"*\").length;\n\t});\n\n\t// Support: IE<9\n\tsupport.getElementsByClassName = rnative.test( document.getElementsByClassName );\n\n\t// Support: IE<10\n\t// Check if getElementById returns elements by name\n\t// The broken getElementById methods don't pick up programatically-set names,\n\t// so use a roundabout getElementsByName test\n\tsupport.getById = assert(function( div ) {\n\t\tdocElem.appendChild( div ).id = expando;\n\t\treturn !document.getElementsByName || !document.getElementsByName( expando ).length;\n\t});\n\n\t// ID find and filter\n\tif ( support.getById ) {\n\t\tExpr.find[\"ID\"] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar m = context.getElementById( id );\n\t\t\t\treturn m ? [ m ] : [];\n\t\t\t}\n\t\t};\n\t\tExpr.filter[\"ID\"] = function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.getAttribute(\"id\") === attrId;\n\t\t\t};\n\t\t};\n\t} else {\n\t\t// Support: IE6/7\n\t\t// getElementById is not reliable as a find shortcut\n\t\tdelete Expr.find[\"ID\"];\n\n\t\tExpr.filter[\"ID\"] =  function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\tvar node = typeof elem.getAttributeNode !== \"undefined\" &&\n\t\t\t\t\telem.getAttributeNode(\"id\");\n\t\t\t\treturn node && node.value === attrId;\n\t\t\t};\n\t\t};\n\t}\n\n\t// Tag\n\tExpr.find[\"TAG\"] = support.getElementsByTagName ?\n\t\tfunction( tag, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\t\t\treturn context.getElementsByTagName( tag );\n\n\t\t\t// DocumentFragment nodes don't have gEBTN\n\t\t\t} else if ( support.qsa ) {\n\t\t\t\treturn context.querySelectorAll( tag );\n\t\t\t}\n\t\t} :\n\n\t\tfunction( tag, context ) {\n\t\t\tvar elem,\n\t\t\t\ttmp = [],\n\t\t\t\ti = 0,\n\t\t\t\t// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too\n\t\t\t\tresults = context.getElementsByTagName( tag );\n\n\t\t\t// Filter out possible comments\n\t\t\tif ( tag === \"*\" ) {\n\t\t\t\twhile ( (elem = results[i++]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\ttmp.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn tmp;\n\t\t\t}\n\t\t\treturn results;\n\t\t};\n\n\t// Class\n\tExpr.find[\"CLASS\"] = support.getElementsByClassName && function( className, context ) {\n\t\tif ( typeof context.getElementsByClassName !== \"undefined\" && documentIsHTML ) {\n\t\t\treturn context.getElementsByClassName( className );\n\t\t}\n\t};\n\n\t/* QSA/matchesSelector\n\t---------------------------------------------------------------------- */\n\n\t// QSA and matchesSelector support\n\n\t// matchesSelector(:active) reports false when true (IE9/Opera 11.5)\n\trbuggyMatches = [];\n\n\t// qSa(:focus) reports false when true (Chrome 21)\n\t// We allow this because of a bug in IE8/9 that throws an error\n\t// whenever `document.activeElement` is accessed on an iframe\n\t// So, we allow :focus to pass through QSA all the time to avoid the IE error\n\t// See http://bugs.jquery.com/ticket/13378\n\trbuggyQSA = [];\n\n\tif ( (support.qsa = rnative.test( document.querySelectorAll )) ) {\n\t\t// Build QSA regex\n\t\t// Regex strategy adopted from Diego Perini\n\t\tassert(function( div ) {\n\t\t\t// Select is set to empty string on purpose\n\t\t\t// This is to test IE's treatment of not explicitly\n\t\t\t// setting a boolean content attribute,\n\t\t\t// since its presence should be enough\n\t\t\t// http://bugs.jquery.com/ticket/12359\n\t\t\tdocElem.appendChild( div ).innerHTML = \"<a id='\" + expando + \"'></a>\" +\n\t\t\t\t\"<select id='\" + expando + \"-\\r\\\\' msallowcapture=''>\" +\n\t\t\t\t\"<option selected=''></option></select>\";\n\n\t\t\t// Support: IE8, Opera 11-12.16\n\t\t\t// Nothing should be selected when empty strings follow ^= or $= or *=\n\t\t\t// The test attribute must be unknown in Opera but \"safe\" for WinRT\n\t\t\t// http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section\n\t\t\tif ( div.querySelectorAll(\"[msallowcapture^='']\").length ) {\n\t\t\t\trbuggyQSA.push( \"[*^$]=\" + whitespace + \"*(?:''|\\\"\\\")\" );\n\t\t\t}\n\n\t\t\t// Support: IE8\n\t\t\t// Boolean attributes and \"value\" are not treated correctly\n\t\t\tif ( !div.querySelectorAll(\"[selected]\").length ) {\n\t\t\t\trbuggyQSA.push( \"\\\\[\" + whitespace + \"*(?:value|\" + booleans + \")\" );\n\t\t\t}\n\n\t\t\t// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+\n\t\t\tif ( !div.querySelectorAll( \"[id~=\" + expando + \"-]\" ).length ) {\n\t\t\t\trbuggyQSA.push(\"~=\");\n\t\t\t}\n\n\t\t\t// Webkit/Opera - :checked should return selected option elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !div.querySelectorAll(\":checked\").length ) {\n\t\t\t\trbuggyQSA.push(\":checked\");\n\t\t\t}\n\n\t\t\t// Support: Safari 8+, iOS 8+\n\t\t\t// https://bugs.webkit.org/show_bug.cgi?id=136851\n\t\t\t// In-page `selector#id sibing-combinator selector` fails\n\t\t\tif ( !div.querySelectorAll( \"a#\" + expando + \"+*\" ).length ) {\n\t\t\t\trbuggyQSA.push(\".#.+[+~]\");\n\t\t\t}\n\t\t});\n\n\t\tassert(function( div ) {\n\t\t\t// Support: Windows 8 Native Apps\n\t\t\t// The type and name attributes are restricted during .innerHTML assignment\n\t\t\tvar input = document.createElement(\"input\");\n\t\t\tinput.setAttribute( \"type\", \"hidden\" );\n\t\t\tdiv.appendChild( input ).setAttribute( \"name\", \"D\" );\n\n\t\t\t// Support: IE8\n\t\t\t// Enforce case-sensitivity of name attribute\n\t\t\tif ( div.querySelectorAll(\"[name=d]\").length ) {\n\t\t\t\trbuggyQSA.push( \"name\" + whitespace + \"*[*^$|!~]?=\" );\n\t\t\t}\n\n\t\t\t// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !div.querySelectorAll(\":enabled\").length ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Opera 10-11 does not throw on post-comma invalid pseudos\n\t\t\tdiv.querySelectorAll(\"*,:x\");\n\t\t\trbuggyQSA.push(\",.*:\");\n\t\t});\n\t}\n\n\tif ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||\n\t\tdocElem.webkitMatchesSelector ||\n\t\tdocElem.mozMatchesSelector ||\n\t\tdocElem.oMatchesSelector ||\n\t\tdocElem.msMatchesSelector) )) ) {\n\n\t\tassert(function( div ) {\n\t\t\t// Check to see if it's possible to do matchesSelector\n\t\t\t// on a disconnected node (IE 9)\n\t\t\tsupport.disconnectedMatch = matches.call( div, \"div\" );\n\n\t\t\t// This should fail with an exception\n\t\t\t// Gecko does not error, returns false instead\n\t\t\tmatches.call( div, \"[s!='']:x\" );\n\t\t\trbuggyMatches.push( \"!=\", pseudos );\n\t\t});\n\t}\n\n\trbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join(\"|\") );\n\trbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join(\"|\") );\n\n\t/* Contains\n\t---------------------------------------------------------------------- */\n\thasCompare = rnative.test( docElem.compareDocumentPosition );\n\n\t// Element contains another\n\t// Purposefully self-exclusive\n\t// As in, an element does not contain itself\n\tcontains = hasCompare || rnative.test( docElem.contains ) ?\n\t\tfunction( a, b ) {\n\t\t\tvar adown = a.nodeType === 9 ? a.documentElement : a,\n\t\t\t\tbup = b && b.parentNode;\n\t\t\treturn a === bup || !!( bup && bup.nodeType === 1 && (\n\t\t\t\tadown.contains ?\n\t\t\t\t\tadown.contains( bup ) :\n\t\t\t\t\ta.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16\n\t\t\t));\n\t\t} :\n\t\tfunction( a, b ) {\n\t\t\tif ( b ) {\n\t\t\t\twhile ( (b = b.parentNode) ) {\n\t\t\t\t\tif ( b === a ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\n\t/* Sorting\n\t---------------------------------------------------------------------- */\n\n\t// Document order sorting\n\tsortOrder = hasCompare ?\n\tfunction( a, b ) {\n\n\t\t// Flag for duplicate removal\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Sort on method existence if only one input has compareDocumentPosition\n\t\tvar compare = !a.compareDocumentPosition - !b.compareDocumentPosition;\n\t\tif ( compare ) {\n\t\t\treturn compare;\n\t\t}\n\n\t\t// Calculate position if both inputs belong to the same document\n\t\tcompare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?\n\t\t\ta.compareDocumentPosition( b ) :\n\n\t\t\t// Otherwise we know they are disconnected\n\t\t\t1;\n\n\t\t// Disconnected nodes\n\t\tif ( compare & 1 ||\n\t\t\t(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {\n\n\t\t\t// Choose the first element that is related to our preferred document\n\t\t\tif ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tif ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\t// Maintain original order\n\t\t\treturn sortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\t\t}\n\n\t\treturn compare & 4 ? -1 : 1;\n\t} :\n\tfunction( a, b ) {\n\t\t// Exit early if the nodes are identical\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\taup = a.parentNode,\n\t\t\tbup = b.parentNode,\n\t\t\tap = [ a ],\n\t\t\tbp = [ b ];\n\n\t\t// Parentless nodes are either documents or disconnected\n\t\tif ( !aup || !bup ) {\n\t\t\treturn a === document ? -1 :\n\t\t\t\tb === document ? 1 :\n\t\t\t\taup ? -1 :\n\t\t\t\tbup ? 1 :\n\t\t\t\tsortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\n\t\t// If the nodes are siblings, we can do a quick check\n\t\t} else if ( aup === bup ) {\n\t\t\treturn siblingCheck( a, b );\n\t\t}\n\n\t\t// Otherwise we need full lists of their ancestors for comparison\n\t\tcur = a;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tap.unshift( cur );\n\t\t}\n\t\tcur = b;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tbp.unshift( cur );\n\t\t}\n\n\t\t// Walk down the tree looking for a discrepancy\n\t\twhile ( ap[i] === bp[i] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i ?\n\t\t\t// Do a sibling check if the nodes have a common ancestor\n\t\t\tsiblingCheck( ap[i], bp[i] ) :\n\n\t\t\t// Otherwise nodes in our document sort first\n\t\t\tap[i] === preferredDoc ? -1 :\n\t\t\tbp[i] === preferredDoc ? 1 :\n\t\t\t0;\n\t};\n\n\treturn document;\n};\n\nSizzle.matches = function( expr, elements ) {\n\treturn Sizzle( expr, null, null, elements );\n};\n\nSizzle.matchesSelector = function( elem, expr ) {\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\t// Make sure that attribute selectors are quoted\n\texpr = expr.replace( rattributeQuotes, \"='$1']\" );\n\n\tif ( support.matchesSelector && documentIsHTML &&\n\t\t!compilerCache[ expr + \" \" ] &&\n\t\t( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&\n\t\t( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {\n\n\t\ttry {\n\t\t\tvar ret = matches.call( elem, expr );\n\n\t\t\t// IE 9's matchesSelector returns false on disconnected nodes\n\t\t\tif ( ret || support.disconnectedMatch ||\n\t\t\t\t\t// As well, disconnected nodes are said to be in a document\n\t\t\t\t\t// fragment in IE 9\n\t\t\t\t\telem.document && elem.document.nodeType !== 11 ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t} catch (e) {}\n\t}\n\n\treturn Sizzle( expr, document, null, [ elem ] ).length > 0;\n};\n\nSizzle.contains = function( context, elem ) {\n\t// Set document vars if needed\n\tif ( ( context.ownerDocument || context ) !== document ) {\n\t\tsetDocument( context );\n\t}\n\treturn contains( context, elem );\n};\n\nSizzle.attr = function( elem, name ) {\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\tvar fn = Expr.attrHandle[ name.toLowerCase() ],\n\t\t// Don't get fooled by Object.prototype properties (jQuery #13807)\n\t\tval = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?\n\t\t\tfn( elem, name, !documentIsHTML ) :\n\t\t\tundefined;\n\n\treturn val !== undefined ?\n\t\tval :\n\t\tsupport.attributes || !documentIsHTML ?\n\t\t\telem.getAttribute( name ) :\n\t\t\t(val = elem.getAttributeNode(name)) && val.specified ?\n\t\t\t\tval.value :\n\t\t\t\tnull;\n};\n\nSizzle.error = function( msg ) {\n\tthrow new Error( \"Syntax error, unrecognized expression: \" + msg );\n};\n\n/**\n * Document sorting and removing duplicates\n * @param {ArrayLike} results\n */\nSizzle.uniqueSort = function( results ) {\n\tvar elem,\n\t\tduplicates = [],\n\t\tj = 0,\n\t\ti = 0;\n\n\t// Unless we *know* we can detect duplicates, assume their presence\n\thasDuplicate = !support.detectDuplicates;\n\tsortInput = !support.sortStable && results.slice( 0 );\n\tresults.sort( sortOrder );\n\n\tif ( hasDuplicate ) {\n\t\twhile ( (elem = results[i++]) ) {\n\t\t\tif ( elem === results[ i ] ) {\n\t\t\t\tj = duplicates.push( i );\n\t\t\t}\n\t\t}\n\t\twhile ( j-- ) {\n\t\t\tresults.splice( duplicates[ j ], 1 );\n\t\t}\n\t}\n\n\t// Clear input after sorting to release objects\n\t// See https://github.com/jquery/sizzle/pull/225\n\tsortInput = null;\n\n\treturn results;\n};\n\n/**\n * Utility function for retrieving the text value of an array of DOM nodes\n * @param {Array|Element} elem\n */\ngetText = Sizzle.getText = function( elem ) {\n\tvar node,\n\t\tret = \"\",\n\t\ti = 0,\n\t\tnodeType = elem.nodeType;\n\n\tif ( !nodeType ) {\n\t\t// If no nodeType, this is expected to be an array\n\t\twhile ( (node = elem[i++]) ) {\n\t\t\t// Do not traverse comment nodes\n\t\t\tret += getText( node );\n\t\t}\n\t} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {\n\t\t// Use textContent for elements\n\t\t// innerText usage removed for consistency of new lines (jQuery #11153)\n\t\tif ( typeof elem.textContent === \"string\" ) {\n\t\t\treturn elem.textContent;\n\t\t} else {\n\t\t\t// Traverse its children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tret += getText( elem );\n\t\t\t}\n\t\t}\n\t} else if ( nodeType === 3 || nodeType === 4 ) {\n\t\treturn elem.nodeValue;\n\t}\n\t// Do not include comment or processing instruction nodes\n\n\treturn ret;\n};\n\nExpr = Sizzle.selectors = {\n\n\t// Can be adjusted by the user\n\tcacheLength: 50,\n\n\tcreatePseudo: markFunction,\n\n\tmatch: matchExpr,\n\n\tattrHandle: {},\n\n\tfind: {},\n\n\trelative: {\n\t\t\">\": { dir: \"parentNode\", first: true },\n\t\t\" \": { dir: \"parentNode\" },\n\t\t\"+\": { dir: \"previousSibling\", first: true },\n\t\t\"~\": { dir: \"previousSibling\" }\n\t},\n\n\tpreFilter: {\n\t\t\"ATTR\": function( match ) {\n\t\t\tmatch[1] = match[1].replace( runescape, funescape );\n\n\t\t\t// Move the given value to match[3] whether quoted or unquoted\n\t\t\tmatch[3] = ( match[3] || match[4] || match[5] || \"\" ).replace( runescape, funescape );\n\n\t\t\tif ( match[2] === \"~=\" ) {\n\t\t\t\tmatch[3] = \" \" + match[3] + \" \";\n\t\t\t}\n\n\t\t\treturn match.slice( 0, 4 );\n\t\t},\n\n\t\t\"CHILD\": function( match ) {\n\t\t\t/* matches from matchExpr[\"CHILD\"]\n\t\t\t\t1 type (only|nth|...)\n\t\t\t\t2 what (child|of-type)\n\t\t\t\t3 argument (even|odd|\\d*|\\d*n([+-]\\d+)?|...)\n\t\t\t\t4 xn-component of xn+y argument ([+-]?\\d*n|)\n\t\t\t\t5 sign of xn-component\n\t\t\t\t6 x of xn-component\n\t\t\t\t7 sign of y-component\n\t\t\t\t8 y of y-component\n\t\t\t*/\n\t\t\tmatch[1] = match[1].toLowerCase();\n\n\t\t\tif ( match[1].slice( 0, 3 ) === \"nth\" ) {\n\t\t\t\t// nth-* requires argument\n\t\t\t\tif ( !match[3] ) {\n\t\t\t\t\tSizzle.error( match[0] );\n\t\t\t\t}\n\n\t\t\t\t// numeric x and y parameters for Expr.filter.CHILD\n\t\t\t\t// remember that false/true cast respectively to 0/1\n\t\t\t\tmatch[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === \"even\" || match[3] === \"odd\" ) );\n\t\t\t\tmatch[5] = +( ( match[7] + match[8] ) || match[3] === \"odd\" );\n\n\t\t\t// other types prohibit arguments\n\t\t\t} else if ( match[3] ) {\n\t\t\t\tSizzle.error( match[0] );\n\t\t\t}\n\n\t\t\treturn match;\n\t\t},\n\n\t\t\"PSEUDO\": function( match ) {\n\t\t\tvar excess,\n\t\t\t\tunquoted = !match[6] && match[2];\n\n\t\t\tif ( matchExpr[\"CHILD\"].test( match[0] ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Accept quoted arguments as-is\n\t\t\tif ( match[3] ) {\n\t\t\t\tmatch[2] = match[4] || match[5] || \"\";\n\n\t\t\t// Strip excess characters from unquoted arguments\n\t\t\t} else if ( unquoted && rpseudo.test( unquoted ) &&\n\t\t\t\t// Get excess from tokenize (recursively)\n\t\t\t\t(excess = tokenize( unquoted, true )) &&\n\t\t\t\t// advance to the next closing parenthesis\n\t\t\t\t(excess = unquoted.indexOf( \")\", unquoted.length - excess ) - unquoted.length) ) {\n\n\t\t\t\t// excess is a negative index\n\t\t\t\tmatch[0] = match[0].slice( 0, excess );\n\t\t\t\tmatch[2] = unquoted.slice( 0, excess );\n\t\t\t}\n\n\t\t\t// Return only captures needed by the pseudo filter method (type and argument)\n\t\t\treturn match.slice( 0, 3 );\n\t\t}\n\t},\n\n\tfilter: {\n\n\t\t\"TAG\": function( nodeNameSelector ) {\n\t\t\tvar nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn nodeNameSelector === \"*\" ?\n\t\t\t\tfunction() { return true; } :\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === nodeName;\n\t\t\t\t};\n\t\t},\n\n\t\t\"CLASS\": function( className ) {\n\t\t\tvar pattern = classCache[ className + \" \" ];\n\n\t\t\treturn pattern ||\n\t\t\t\t(pattern = new RegExp( \"(^|\" + whitespace + \")\" + className + \"(\" + whitespace + \"|$)\" )) &&\n\t\t\t\tclassCache( className, function( elem ) {\n\t\t\t\t\treturn pattern.test( typeof elem.className === \"string\" && elem.className || typeof elem.getAttribute !== \"undefined\" && elem.getAttribute(\"class\") || \"\" );\n\t\t\t\t});\n\t\t},\n\n\t\t\"ATTR\": function( name, operator, check ) {\n\t\t\treturn function( elem ) {\n\t\t\t\tvar result = Sizzle.attr( elem, name );\n\n\t\t\t\tif ( result == null ) {\n\t\t\t\t\treturn operator === \"!=\";\n\t\t\t\t}\n\t\t\t\tif ( !operator ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tresult += \"\";\n\n\t\t\t\treturn operator === \"=\" ? result === check :\n\t\t\t\t\toperator === \"!=\" ? result !== check :\n\t\t\t\t\toperator === \"^=\" ? check && result.indexOf( check ) === 0 :\n\t\t\t\t\toperator === \"*=\" ? check && result.indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"$=\" ? check && result.slice( -check.length ) === check :\n\t\t\t\t\toperator === \"~=\" ? ( \" \" + result.replace( rwhitespace, \" \" ) + \" \" ).indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"|=\" ? result === check || result.slice( 0, check.length + 1 ) === check + \"-\" :\n\t\t\t\t\tfalse;\n\t\t\t};\n\t\t},\n\n\t\t\"CHILD\": function( type, what, argument, first, last ) {\n\t\t\tvar simple = type.slice( 0, 3 ) !== \"nth\",\n\t\t\t\tforward = type.slice( -4 ) !== \"last\",\n\t\t\t\tofType = what === \"of-type\";\n\n\t\t\treturn first === 1 && last === 0 ?\n\n\t\t\t\t// Shortcut for :nth-*(n)\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn !!elem.parentNode;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tvar cache, uniqueCache, outerCache, node, nodeIndex, start,\n\t\t\t\t\t\tdir = simple !== forward ? \"nextSibling\" : \"previousSibling\",\n\t\t\t\t\t\tparent = elem.parentNode,\n\t\t\t\t\t\tname = ofType && elem.nodeName.toLowerCase(),\n\t\t\t\t\t\tuseCache = !xml && !ofType,\n\t\t\t\t\t\tdiff = false;\n\n\t\t\t\t\tif ( parent ) {\n\n\t\t\t\t\t\t// :(first|last|only)-(child|of-type)\n\t\t\t\t\t\tif ( simple ) {\n\t\t\t\t\t\t\twhile ( dir ) {\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\twhile ( (node = node[ dir ]) ) {\n\t\t\t\t\t\t\t\t\tif ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnode.nodeName.toLowerCase() === name :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) {\n\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// Reverse direction for :only-* (if we haven't yet done so)\n\t\t\t\t\t\t\t\tstart = dir = type === \"only\" && !start && \"nextSibling\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstart = [ forward ? parent.firstChild : parent.lastChild ];\n\n\t\t\t\t\t\t// non-xml :nth-child(...) stores cache data on `parent`\n\t\t\t\t\t\tif ( forward && useCache ) {\n\n\t\t\t\t\t\t\t// Seek `elem` from a previously-cached index\n\n\t\t\t\t\t\t\t// ...in a gzip-friendly way\n\t\t\t\t\t\t\tnode = parent;\n\t\t\t\t\t\t\touterCache = node[ expando ] || (node[ expando ] = {});\n\n\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t(outerCache[ node.uniqueID ] = {});\n\n\t\t\t\t\t\t\tcache = uniqueCache[ type ] || [];\n\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\tdiff = nodeIndex && cache[ 2 ];\n\t\t\t\t\t\t\tnode = nodeIndex && parent.childNodes[ nodeIndex ];\n\n\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\n\t\t\t\t\t\t\t\t// Fallback to seeking `elem` from the start\n\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\t// When found, cache indexes on `parent` and break\n\t\t\t\t\t\t\t\tif ( node.nodeType === 1 && ++diff && node === elem ) {\n\t\t\t\t\t\t\t\t\tuniqueCache[ type ] = [ dirruns, nodeIndex, diff ];\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Use previously-cached element index if available\n\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t// ...in a gzip-friendly way\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\touterCache = node[ expando ] || (node[ expando ] = {});\n\n\t\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t\t(outerCache[ node.uniqueID ] = {});\n\n\t\t\t\t\t\t\t\tcache = uniqueCache[ type ] || [];\n\t\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\t\tdiff = nodeIndex;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// xml :nth-child(...)\n\t\t\t\t\t\t\t// or :nth-last-child(...) or :nth(-last)?-of-type(...)\n\t\t\t\t\t\t\tif ( diff === false ) {\n\t\t\t\t\t\t\t\t// Use the same loop as above to seek `elem` from the start\n\t\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\t\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\t\tif ( ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnode.nodeName.toLowerCase() === name :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) &&\n\t\t\t\t\t\t\t\t\t\t++diff ) {\n\n\t\t\t\t\t\t\t\t\t\t// Cache the index of each encountered element\n\t\t\t\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t\t\t\touterCache = node[ expando ] || (node[ expando ] = {});\n\n\t\t\t\t\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t\t\t\t\t(outerCache[ node.uniqueID ] = {});\n\n\t\t\t\t\t\t\t\t\t\t\tuniqueCache[ type ] = [ dirruns, diff ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif ( node === elem ) {\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Incorporate the offset, then check against cycle size\n\t\t\t\t\t\tdiff -= last;\n\t\t\t\t\t\treturn diff === first || ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t},\n\n\t\t\"PSEUDO\": function( pseudo, argument ) {\n\t\t\t// pseudo-class names are case-insensitive\n\t\t\t// http://www.w3.org/TR/selectors/#pseudo-classes\n\t\t\t// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters\n\t\t\t// Remember that setFilters inherits from pseudos\n\t\t\tvar args,\n\t\t\t\tfn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||\n\t\t\t\t\tSizzle.error( \"unsupported pseudo: \" + pseudo );\n\n\t\t\t// The user may use createPseudo to indicate that\n\t\t\t// arguments are needed to create the filter function\n\t\t\t// just as Sizzle does\n\t\t\tif ( fn[ expando ] ) {\n\t\t\t\treturn fn( argument );\n\t\t\t}\n\n\t\t\t// But maintain support for old signatures\n\t\t\tif ( fn.length > 1 ) {\n\t\t\t\targs = [ pseudo, pseudo, \"\", argument ];\n\t\t\t\treturn Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?\n\t\t\t\t\tmarkFunction(function( seed, matches ) {\n\t\t\t\t\t\tvar idx,\n\t\t\t\t\t\t\tmatched = fn( seed, argument ),\n\t\t\t\t\t\t\ti = matched.length;\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tidx = indexOf( seed, matched[i] );\n\t\t\t\t\t\t\tseed[ idx ] = !( matches[ idx ] = matched[i] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}) :\n\t\t\t\t\tfunction( elem ) {\n\t\t\t\t\t\treturn fn( elem, 0, args );\n\t\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn fn;\n\t\t}\n\t},\n\n\tpseudos: {\n\t\t// Potentially complex pseudos\n\t\t\"not\": markFunction(function( selector ) {\n\t\t\t// Trim the selector passed to compile\n\t\t\t// to avoid treating leading and trailing\n\t\t\t// spaces as combinators\n\t\t\tvar input = [],\n\t\t\t\tresults = [],\n\t\t\t\tmatcher = compile( selector.replace( rtrim, \"$1\" ) );\n\n\t\t\treturn matcher[ expando ] ?\n\t\t\t\tmarkFunction(function( seed, matches, context, xml ) {\n\t\t\t\t\tvar elem,\n\t\t\t\t\t\tunmatched = matcher( seed, null, xml, [] ),\n\t\t\t\t\t\ti = seed.length;\n\n\t\t\t\t\t// Match elements unmatched by `matcher`\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = unmatched[i]) ) {\n\t\t\t\t\t\t\tseed[i] = !(matches[i] = elem);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}) :\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tinput[0] = elem;\n\t\t\t\t\tmatcher( input, null, xml, results );\n\t\t\t\t\t// Don't keep the element (issue #299)\n\t\t\t\t\tinput[0] = null;\n\t\t\t\t\treturn !results.pop();\n\t\t\t\t};\n\t\t}),\n\n\t\t\"has\": markFunction(function( selector ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn Sizzle( selector, elem ).length > 0;\n\t\t\t};\n\t\t}),\n\n\t\t\"contains\": markFunction(function( text ) {\n\t\t\ttext = text.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;\n\t\t\t};\n\t\t}),\n\n\t\t// \"Whether an element is represented by a :lang() selector\n\t\t// is based solely on the element's language value\n\t\t// being equal to the identifier C,\n\t\t// or beginning with the identifier C immediately followed by \"-\".\n\t\t// The matching of C against the element's language value is performed case-insensitively.\n\t\t// The identifier C does not have to be a valid language name.\"\n\t\t// http://www.w3.org/TR/selectors/#lang-pseudo\n\t\t\"lang\": markFunction( function( lang ) {\n\t\t\t// lang value must be a valid identifier\n\t\t\tif ( !ridentifier.test(lang || \"\") ) {\n\t\t\t\tSizzle.error( \"unsupported lang: \" + lang );\n\t\t\t}\n\t\t\tlang = lang.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\tvar elemLang;\n\t\t\t\tdo {\n\t\t\t\t\tif ( (elemLang = documentIsHTML ?\n\t\t\t\t\t\telem.lang :\n\t\t\t\t\t\telem.getAttribute(\"xml:lang\") || elem.getAttribute(\"lang\")) ) {\n\n\t\t\t\t\t\telemLang = elemLang.toLowerCase();\n\t\t\t\t\t\treturn elemLang === lang || elemLang.indexOf( lang + \"-\" ) === 0;\n\t\t\t\t\t}\n\t\t\t\t} while ( (elem = elem.parentNode) && elem.nodeType === 1 );\n\t\t\t\treturn false;\n\t\t\t};\n\t\t}),\n\n\t\t// Miscellaneous\n\t\t\"target\": function( elem ) {\n\t\t\tvar hash = window.location && window.location.hash;\n\t\t\treturn hash && hash.slice( 1 ) === elem.id;\n\t\t},\n\n\t\t\"root\": function( elem ) {\n\t\t\treturn elem === docElem;\n\t\t},\n\n\t\t\"focus\": function( elem ) {\n\t\t\treturn elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);\n\t\t},\n\n\t\t// Boolean properties\n\t\t\"enabled\": function( elem ) {\n\t\t\treturn elem.disabled === false;\n\t\t},\n\n\t\t\"disabled\": function( elem ) {\n\t\t\treturn elem.disabled === true;\n\t\t},\n\n\t\t\"checked\": function( elem ) {\n\t\t\t// In CSS3, :checked should return both checked and selected elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\tvar nodeName = elem.nodeName.toLowerCase();\n\t\t\treturn (nodeName === \"input\" && !!elem.checked) || (nodeName === \"option\" && !!elem.selected);\n\t\t},\n\n\t\t\"selected\": function( elem ) {\n\t\t\t// Accessing this property makes selected-by-default\n\t\t\t// options in Safari work properly\n\t\t\tif ( elem.parentNode ) {\n\t\t\t\telem.parentNode.selectedIndex;\n\t\t\t}\n\n\t\t\treturn elem.selected === true;\n\t\t},\n\n\t\t// Contents\n\t\t\"empty\": function( elem ) {\n\t\t\t// http://www.w3.org/TR/selectors/#empty-pseudo\n\t\t\t// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),\n\t\t\t//   but not by others (comment: 8; processing instruction: 7; etc.)\n\t\t\t// nodeType < 6 works because attributes (2) do not appear as children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tif ( elem.nodeType < 6 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\t\"parent\": function( elem ) {\n\t\t\treturn !Expr.pseudos[\"empty\"]( elem );\n\t\t},\n\n\t\t// Element/input types\n\t\t\"header\": function( elem ) {\n\t\t\treturn rheader.test( elem.nodeName );\n\t\t},\n\n\t\t\"input\": function( elem ) {\n\t\t\treturn rinputs.test( elem.nodeName );\n\t\t},\n\n\t\t\"button\": function( elem ) {\n\t\t\tvar name = elem.nodeName.toLowerCase();\n\t\t\treturn name === \"input\" && elem.type === \"button\" || name === \"button\";\n\t\t},\n\n\t\t\"text\": function( elem ) {\n\t\t\tvar attr;\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" &&\n\t\t\t\telem.type === \"text\" &&\n\n\t\t\t\t// Support: IE<8\n\t\t\t\t// New HTML5 attribute values (e.g., \"search\") appear with elem.type === \"text\"\n\t\t\t\t( (attr = elem.getAttribute(\"type\")) == null || attr.toLowerCase() === \"text\" );\n\t\t},\n\n\t\t// Position-in-collection\n\t\t\"first\": createPositionalPseudo(function() {\n\t\t\treturn [ 0 ];\n\t\t}),\n\n\t\t\"last\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\treturn [ length - 1 ];\n\t\t}),\n\n\t\t\"eq\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\treturn [ argument < 0 ? argument + length : argument ];\n\t\t}),\n\n\t\t\"even\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"odd\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 1;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"lt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; --i >= 0; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"gt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; ++i < length; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t})\n\t}\n};\n\nExpr.pseudos[\"nth\"] = Expr.pseudos[\"eq\"];\n\n// Add button/input type pseudos\nfor ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {\n\tExpr.pseudos[ i ] = createInputPseudo( i );\n}\nfor ( i in { submit: true, reset: true } ) {\n\tExpr.pseudos[ i ] = createButtonPseudo( i );\n}\n\n// Easy API for creating new setFilters\nfunction setFilters() {}\nsetFilters.prototype = Expr.filters = Expr.pseudos;\nExpr.setFilters = new setFilters();\n\ntokenize = Sizzle.tokenize = function( selector, parseOnly ) {\n\tvar matched, match, tokens, type,\n\t\tsoFar, groups, preFilters,\n\t\tcached = tokenCache[ selector + \" \" ];\n\n\tif ( cached ) {\n\t\treturn parseOnly ? 0 : cached.slice( 0 );\n\t}\n\n\tsoFar = selector;\n\tgroups = [];\n\tpreFilters = Expr.preFilter;\n\n\twhile ( soFar ) {\n\n\t\t// Comma and first run\n\t\tif ( !matched || (match = rcomma.exec( soFar )) ) {\n\t\t\tif ( match ) {\n\t\t\t\t// Don't consume trailing commas as valid\n\t\t\t\tsoFar = soFar.slice( match[0].length ) || soFar;\n\t\t\t}\n\t\t\tgroups.push( (tokens = []) );\n\t\t}\n\n\t\tmatched = false;\n\n\t\t// Combinators\n\t\tif ( (match = rcombinators.exec( soFar )) ) {\n\t\t\tmatched = match.shift();\n\t\t\ttokens.push({\n\t\t\t\tvalue: matched,\n\t\t\t\t// Cast descendant combinators to space\n\t\t\t\ttype: match[0].replace( rtrim, \" \" )\n\t\t\t});\n\t\t\tsoFar = soFar.slice( matched.length );\n\t\t}\n\n\t\t// Filters\n\t\tfor ( type in Expr.filter ) {\n\t\t\tif ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||\n\t\t\t\t(match = preFilters[ type ]( match ))) ) {\n\t\t\t\tmatched = match.shift();\n\t\t\t\ttokens.push({\n\t\t\t\t\tvalue: matched,\n\t\t\t\t\ttype: type,\n\t\t\t\t\tmatches: match\n\t\t\t\t});\n\t\t\t\tsoFar = soFar.slice( matched.length );\n\t\t\t}\n\t\t}\n\n\t\tif ( !matched ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Return the length of the invalid excess\n\t// if we're just parsing\n\t// Otherwise, throw an error or return tokens\n\treturn parseOnly ?\n\t\tsoFar.length :\n\t\tsoFar ?\n\t\t\tSizzle.error( selector ) :\n\t\t\t// Cache the tokens\n\t\t\ttokenCache( selector, groups ).slice( 0 );\n};\n\nfunction toSelector( tokens ) {\n\tvar i = 0,\n\t\tlen = tokens.length,\n\t\tselector = \"\";\n\tfor ( ; i < len; i++ ) {\n\t\tselector += tokens[i].value;\n\t}\n\treturn selector;\n}\n\nfunction addCombinator( matcher, combinator, base ) {\n\tvar dir = combinator.dir,\n\t\tcheckNonElements = base && dir === \"parentNode\",\n\t\tdoneName = done++;\n\n\treturn combinator.first ?\n\t\t// Check against closest ancestor/preceding element\n\t\tfunction( elem, context, xml ) {\n\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\treturn matcher( elem, context, xml );\n\t\t\t\t}\n\t\t\t}\n\t\t} :\n\n\t\t// Check against all ancestor/preceding elements\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar oldCache, uniqueCache, outerCache,\n\t\t\t\tnewCache = [ dirruns, doneName ];\n\n\t\t\t// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching\n\t\t\tif ( xml ) {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\touterCache = elem[ expando ] || (elem[ expando ] = {});\n\n\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\tuniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});\n\n\t\t\t\t\t\tif ( (oldCache = uniqueCache[ dir ]) &&\n\t\t\t\t\t\t\toldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {\n\n\t\t\t\t\t\t\t// Assign to newCache so results back-propagate to previous elements\n\t\t\t\t\t\t\treturn (newCache[ 2 ] = oldCache[ 2 ]);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Reuse newcache so results back-propagate to previous elements\n\t\t\t\t\t\t\tuniqueCache[ dir ] = newCache;\n\n\t\t\t\t\t\t\t// A match means we're done; a fail means we have to keep checking\n\t\t\t\t\t\t\tif ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n}\n\nfunction elementMatcher( matchers ) {\n\treturn matchers.length > 1 ?\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar i = matchers.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( !matchers[i]( elem, context, xml ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t} :\n\t\tmatchers[0];\n}\n\nfunction multipleContexts( selector, contexts, results ) {\n\tvar i = 0,\n\t\tlen = contexts.length;\n\tfor ( ; i < len; i++ ) {\n\t\tSizzle( selector, contexts[i], results );\n\t}\n\treturn results;\n}\n\nfunction condense( unmatched, map, filter, context, xml ) {\n\tvar elem,\n\t\tnewUnmatched = [],\n\t\ti = 0,\n\t\tlen = unmatched.length,\n\t\tmapped = map != null;\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (elem = unmatched[i]) ) {\n\t\t\tif ( !filter || filter( elem, context, xml ) ) {\n\t\t\t\tnewUnmatched.push( elem );\n\t\t\t\tif ( mapped ) {\n\t\t\t\t\tmap.push( i );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn newUnmatched;\n}\n\nfunction setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {\n\tif ( postFilter && !postFilter[ expando ] ) {\n\t\tpostFilter = setMatcher( postFilter );\n\t}\n\tif ( postFinder && !postFinder[ expando ] ) {\n\t\tpostFinder = setMatcher( postFinder, postSelector );\n\t}\n\treturn markFunction(function( seed, results, context, xml ) {\n\t\tvar temp, i, elem,\n\t\t\tpreMap = [],\n\t\t\tpostMap = [],\n\t\t\tpreexisting = results.length,\n\n\t\t\t// Get initial elements from seed or context\n\t\t\telems = seed || multipleContexts( selector || \"*\", context.nodeType ? [ context ] : context, [] ),\n\n\t\t\t// Prefilter to get matcher input, preserving a map for seed-results synchronization\n\t\t\tmatcherIn = preFilter && ( seed || !selector ) ?\n\t\t\t\tcondense( elems, preMap, preFilter, context, xml ) :\n\t\t\t\telems,\n\n\t\t\tmatcherOut = matcher ?\n\t\t\t\t// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,\n\t\t\t\tpostFinder || ( seed ? preFilter : preexisting || postFilter ) ?\n\n\t\t\t\t\t// ...intermediate processing is necessary\n\t\t\t\t\t[] :\n\n\t\t\t\t\t// ...otherwise use results directly\n\t\t\t\t\tresults :\n\t\t\t\tmatcherIn;\n\n\t\t// Find primary matches\n\t\tif ( matcher ) {\n\t\t\tmatcher( matcherIn, matcherOut, context, xml );\n\t\t}\n\n\t\t// Apply postFilter\n\t\tif ( postFilter ) {\n\t\t\ttemp = condense( matcherOut, postMap );\n\t\t\tpostFilter( temp, [], context, xml );\n\n\t\t\t// Un-match failing elements by moving them back to matcherIn\n\t\t\ti = temp.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( (elem = temp[i]) ) {\n\t\t\t\t\tmatcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( seed ) {\n\t\t\tif ( postFinder || preFilter ) {\n\t\t\t\tif ( postFinder ) {\n\t\t\t\t\t// Get the final matcherOut by condensing this intermediate into postFinder contexts\n\t\t\t\t\ttemp = [];\n\t\t\t\t\ti = matcherOut.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = matcherOut[i]) ) {\n\t\t\t\t\t\t\t// Restore matcherIn since elem is not yet a final match\n\t\t\t\t\t\t\ttemp.push( (matcherIn[i] = elem) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpostFinder( null, (matcherOut = []), temp, xml );\n\t\t\t\t}\n\n\t\t\t\t// Move matched elements from seed to results to keep them synchronized\n\t\t\t\ti = matcherOut.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tif ( (elem = matcherOut[i]) &&\n\t\t\t\t\t\t(temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {\n\n\t\t\t\t\t\tseed[temp] = !(results[temp] = elem);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Add elements to results, through postFinder if defined\n\t\t} else {\n\t\t\tmatcherOut = condense(\n\t\t\t\tmatcherOut === results ?\n\t\t\t\t\tmatcherOut.splice( preexisting, matcherOut.length ) :\n\t\t\t\t\tmatcherOut\n\t\t\t);\n\t\t\tif ( postFinder ) {\n\t\t\t\tpostFinder( null, results, matcherOut, xml );\n\t\t\t} else {\n\t\t\t\tpush.apply( results, matcherOut );\n\t\t\t}\n\t\t}\n\t});\n}\n\nfunction matcherFromTokens( tokens ) {\n\tvar checkContext, matcher, j,\n\t\tlen = tokens.length,\n\t\tleadingRelative = Expr.relative[ tokens[0].type ],\n\t\timplicitRelative = leadingRelative || Expr.relative[\" \"],\n\t\ti = leadingRelative ? 1 : 0,\n\n\t\t// The foundational matcher ensures that elements are reachable from top-level context(s)\n\t\tmatchContext = addCombinator( function( elem ) {\n\t\t\treturn elem === checkContext;\n\t\t}, implicitRelative, true ),\n\t\tmatchAnyContext = addCombinator( function( elem ) {\n\t\t\treturn indexOf( checkContext, elem ) > -1;\n\t\t}, implicitRelative, true ),\n\t\tmatchers = [ function( elem, context, xml ) {\n\t\t\tvar ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (\n\t\t\t\t(checkContext = context).nodeType ?\n\t\t\t\t\tmatchContext( elem, context, xml ) :\n\t\t\t\t\tmatchAnyContext( elem, context, xml ) );\n\t\t\t// Avoid hanging onto element (issue #299)\n\t\t\tcheckContext = null;\n\t\t\treturn ret;\n\t\t} ];\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (matcher = Expr.relative[ tokens[i].type ]) ) {\n\t\t\tmatchers = [ addCombinator(elementMatcher( matchers ), matcher) ];\n\t\t} else {\n\t\t\tmatcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );\n\n\t\t\t// Return special upon seeing a positional matcher\n\t\t\tif ( matcher[ expando ] ) {\n\t\t\t\t// Find the next relative operator (if any) for proper handling\n\t\t\t\tj = ++i;\n\t\t\t\tfor ( ; j < len; j++ ) {\n\t\t\t\t\tif ( Expr.relative[ tokens[j].type ] ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn setMatcher(\n\t\t\t\t\ti > 1 && elementMatcher( matchers ),\n\t\t\t\t\ti > 1 && toSelector(\n\t\t\t\t\t\t// If the preceding token was a descendant combinator, insert an implicit any-element `*`\n\t\t\t\t\t\ttokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === \" \" ? \"*\" : \"\" })\n\t\t\t\t\t).replace( rtrim, \"$1\" ),\n\t\t\t\t\tmatcher,\n\t\t\t\t\ti < j && matcherFromTokens( tokens.slice( i, j ) ),\n\t\t\t\t\tj < len && matcherFromTokens( (tokens = tokens.slice( j )) ),\n\t\t\t\t\tj < len && toSelector( tokens )\n\t\t\t\t);\n\t\t\t}\n\t\t\tmatchers.push( matcher );\n\t\t}\n\t}\n\n\treturn elementMatcher( matchers );\n}\n\nfunction matcherFromGroupMatchers( elementMatchers, setMatchers ) {\n\tvar bySet = setMatchers.length > 0,\n\t\tbyElement = elementMatchers.length > 0,\n\t\tsuperMatcher = function( seed, context, xml, results, outermost ) {\n\t\t\tvar elem, j, matcher,\n\t\t\t\tmatchedCount = 0,\n\t\t\t\ti = \"0\",\n\t\t\t\tunmatched = seed && [],\n\t\t\t\tsetMatched = [],\n\t\t\t\tcontextBackup = outermostContext,\n\t\t\t\t// We must always have either seed elements or outermost context\n\t\t\t\telems = seed || byElement && Expr.find[\"TAG\"]( \"*\", outermost ),\n\t\t\t\t// Use integer dirruns iff this is the outermost matcher\n\t\t\t\tdirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),\n\t\t\t\tlen = elems.length;\n\n\t\t\tif ( outermost ) {\n\t\t\t\toutermostContext = context === document || context || outermost;\n\t\t\t}\n\n\t\t\t// Add elements passing elementMatchers directly to results\n\t\t\t// Support: IE<9, Safari\n\t\t\t// Tolerate NodeList properties (IE: \"length\"; Safari: <number>) matching elements by id\n\t\t\tfor ( ; i !== len && (elem = elems[i]) != null; i++ ) {\n\t\t\t\tif ( byElement && elem ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\tif ( !context && elem.ownerDocument !== document ) {\n\t\t\t\t\t\tsetDocument( elem );\n\t\t\t\t\t\txml = !documentIsHTML;\n\t\t\t\t\t}\n\t\t\t\t\twhile ( (matcher = elementMatchers[j++]) ) {\n\t\t\t\t\t\tif ( matcher( elem, context || document, xml) ) {\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( outermost ) {\n\t\t\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Track unmatched elements for set filters\n\t\t\t\tif ( bySet ) {\n\t\t\t\t\t// They will have gone through all possible matchers\n\t\t\t\t\tif ( (elem = !matcher && elem) ) {\n\t\t\t\t\t\tmatchedCount--;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Lengthen the array for every element, matched or not\n\t\t\t\t\tif ( seed ) {\n\t\t\t\t\t\tunmatched.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// `i` is now the count of elements visited above, and adding it to `matchedCount`\n\t\t\t// makes the latter nonnegative.\n\t\t\tmatchedCount += i;\n\n\t\t\t// Apply set filters to unmatched elements\n\t\t\t// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`\n\t\t\t// equals `i`), unless we didn't visit _any_ elements in the above loop because we have\n\t\t\t// no element matchers and no seed.\n\t\t\t// Incrementing an initially-string \"0\" `i` allows `i` to remain a string only in that\n\t\t\t// case, which will result in a \"00\" `matchedCount` that differs from `i` but is also\n\t\t\t// numerically zero.\n\t\t\tif ( bySet && i !== matchedCount ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( (matcher = setMatchers[j++]) ) {\n\t\t\t\t\tmatcher( unmatched, setMatched, context, xml );\n\t\t\t\t}\n\n\t\t\t\tif ( seed ) {\n\t\t\t\t\t// Reintegrate element matches to eliminate the need for sorting\n\t\t\t\t\tif ( matchedCount > 0 ) {\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tif ( !(unmatched[i] || setMatched[i]) ) {\n\t\t\t\t\t\t\t\tsetMatched[i] = pop.call( results );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Discard index placeholder values to get only actual matches\n\t\t\t\t\tsetMatched = condense( setMatched );\n\t\t\t\t}\n\n\t\t\t\t// Add matches to results\n\t\t\t\tpush.apply( results, setMatched );\n\n\t\t\t\t// Seedless set matches succeeding multiple successful matchers stipulate sorting\n\t\t\t\tif ( outermost && !seed && setMatched.length > 0 &&\n\t\t\t\t\t( matchedCount + setMatchers.length ) > 1 ) {\n\n\t\t\t\t\tSizzle.uniqueSort( results );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Override manipulation of globals by nested matchers\n\t\t\tif ( outermost ) {\n\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\toutermostContext = contextBackup;\n\t\t\t}\n\n\t\t\treturn unmatched;\n\t\t};\n\n\treturn bySet ?\n\t\tmarkFunction( superMatcher ) :\n\t\tsuperMatcher;\n}\n\ncompile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {\n\tvar i,\n\t\tsetMatchers = [],\n\t\telementMatchers = [],\n\t\tcached = compilerCache[ selector + \" \" ];\n\n\tif ( !cached ) {\n\t\t// Generate a function of recursive functions that can be used to check each element\n\t\tif ( !match ) {\n\t\t\tmatch = tokenize( selector );\n\t\t}\n\t\ti = match.length;\n\t\twhile ( i-- ) {\n\t\t\tcached = matcherFromTokens( match[i] );\n\t\t\tif ( cached[ expando ] ) {\n\t\t\t\tsetMatchers.push( cached );\n\t\t\t} else {\n\t\t\t\telementMatchers.push( cached );\n\t\t\t}\n\t\t}\n\n\t\t// Cache the compiled function\n\t\tcached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );\n\n\t\t// Save selector and tokenization\n\t\tcached.selector = selector;\n\t}\n\treturn cached;\n};\n\n/**\n * A low-level selection function that works with Sizzle's compiled\n *  selector functions\n * @param {String|Function} selector A selector or a pre-compiled\n *  selector function built with Sizzle.compile\n * @param {Element} context\n * @param {Array} [results]\n * @param {Array} [seed] A set of elements to match against\n */\nselect = Sizzle.select = function( selector, context, results, seed ) {\n\tvar i, tokens, token, type, find,\n\t\tcompiled = typeof selector === \"function\" && selector,\n\t\tmatch = !seed && tokenize( (selector = compiled.selector || selector) );\n\n\tresults = results || [];\n\n\t// Try to minimize operations if there is only one selector in the list and no seed\n\t// (the latter of which guarantees us context)\n\tif ( match.length === 1 ) {\n\n\t\t// Reduce context if the leading compound selector is an ID\n\t\ttokens = match[0] = match[0].slice( 0 );\n\t\tif ( tokens.length > 2 && (token = tokens[0]).type === \"ID\" &&\n\t\t\t\tsupport.getById && context.nodeType === 9 && documentIsHTML &&\n\t\t\t\tExpr.relative[ tokens[1].type ] ) {\n\n\t\t\tcontext = ( Expr.find[\"ID\"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];\n\t\t\tif ( !context ) {\n\t\t\t\treturn results;\n\n\t\t\t// Precompiled matchers will still verify ancestry, so step up a level\n\t\t\t} else if ( compiled ) {\n\t\t\t\tcontext = context.parentNode;\n\t\t\t}\n\n\t\t\tselector = selector.slice( tokens.shift().value.length );\n\t\t}\n\n\t\t// Fetch a seed set for right-to-left matching\n\t\ti = matchExpr[\"needsContext\"].test( selector ) ? 0 : tokens.length;\n\t\twhile ( i-- ) {\n\t\t\ttoken = tokens[i];\n\n\t\t\t// Abort if we hit a combinator\n\t\t\tif ( Expr.relative[ (type = token.type) ] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( (find = Expr.find[ type ]) ) {\n\t\t\t\t// Search, expanding context for leading sibling combinators\n\t\t\t\tif ( (seed = find(\n\t\t\t\t\ttoken.matches[0].replace( runescape, funescape ),\n\t\t\t\t\trsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context\n\t\t\t\t)) ) {\n\n\t\t\t\t\t// If seed is empty or no tokens remain, we can return early\n\t\t\t\t\ttokens.splice( i, 1 );\n\t\t\t\t\tselector = seed.length && toSelector( tokens );\n\t\t\t\t\tif ( !selector ) {\n\t\t\t\t\t\tpush.apply( results, seed );\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compile and execute a filtering function if one is not provided\n\t// Provide `match` to avoid retokenization if we modified the selector above\n\t( compiled || compile( selector, match ) )(\n\t\tseed,\n\t\tcontext,\n\t\t!documentIsHTML,\n\t\tresults,\n\t\t!context || rsibling.test( selector ) && testContext( context.parentNode ) || context\n\t);\n\treturn results;\n};\n\n// One-time assignments\n\n// Sort stability\nsupport.sortStable = expando.split(\"\").sort( sortOrder ).join(\"\") === expando;\n\n// Support: Chrome 14-35+\n// Always assume duplicates if they aren't passed to the comparison function\nsupport.detectDuplicates = !!hasDuplicate;\n\n// Initialize against the default document\nsetDocument();\n\n// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)\n// Detached nodes confoundingly follow *each other*\nsupport.sortDetached = assert(function( div1 ) {\n\t// Should return 1, but returns 4 (following)\n\treturn div1.compareDocumentPosition( document.createElement(\"div\") ) & 1;\n});\n\n// Support: IE<8\n// Prevent attribute/property \"interpolation\"\n// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx\nif ( !assert(function( div ) {\n\tdiv.innerHTML = \"<a href='#'></a>\";\n\treturn div.firstChild.getAttribute(\"href\") === \"#\" ;\n}) ) {\n\taddHandle( \"type|href|height|width\", function( elem, name, isXML ) {\n\t\tif ( !isXML ) {\n\t\t\treturn elem.getAttribute( name, name.toLowerCase() === \"type\" ? 1 : 2 );\n\t\t}\n\t});\n}\n\n// Support: IE<9\n// Use defaultValue in place of getAttribute(\"value\")\nif ( !support.attributes || !assert(function( div ) {\n\tdiv.innerHTML = \"<input/>\";\n\tdiv.firstChild.setAttribute( \"value\", \"\" );\n\treturn div.firstChild.getAttribute( \"value\" ) === \"\";\n}) ) {\n\taddHandle( \"value\", function( elem, name, isXML ) {\n\t\tif ( !isXML && elem.nodeName.toLowerCase() === \"input\" ) {\n\t\t\treturn elem.defaultValue;\n\t\t}\n\t});\n}\n\n// Support: IE<9\n// Use getAttributeNode to fetch booleans when getAttribute lies\nif ( !assert(function( div ) {\n\treturn div.getAttribute(\"disabled\") == null;\n}) ) {\n\taddHandle( booleans, function( elem, name, isXML ) {\n\t\tvar val;\n\t\tif ( !isXML ) {\n\t\t\treturn elem[ name ] === true ? name.toLowerCase() :\n\t\t\t\t\t(val = elem.getAttributeNode( name )) && val.specified ?\n\t\t\t\t\tval.value :\n\t\t\t\tnull;\n\t\t}\n\t});\n}\n\nreturn Sizzle;\n\n})( window );\n\n\n\njQuery.find = Sizzle;\njQuery.expr = Sizzle.selectors;\njQuery.expr[ \":\" ] = jQuery.expr.pseudos;\njQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;\njQuery.text = Sizzle.getText;\njQuery.isXMLDoc = Sizzle.isXML;\njQuery.contains = Sizzle.contains;\n\n\n\nvar dir = function( elem, dir, until ) {\n\tvar matched = [],\n\t\ttruncate = until !== undefined;\n\n\twhile ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {\n\t\tif ( elem.nodeType === 1 ) {\n\t\t\tif ( truncate && jQuery( elem ).is( until ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tmatched.push( elem );\n\t\t}\n\t}\n\treturn matched;\n};\n\n\nvar siblings = function( n, elem ) {\n\tvar matched = [];\n\n\tfor ( ; n; n = n.nextSibling ) {\n\t\tif ( n.nodeType === 1 && n !== elem ) {\n\t\t\tmatched.push( n );\n\t\t}\n\t}\n\n\treturn matched;\n};\n\n\nvar rneedsContext = jQuery.expr.match.needsContext;\n\nvar rsingleTag = ( /^<([\\w-]+)\\s*\\/?>(?:<\\/\\1>|)$/ );\n\n\n\nvar risSimple = /^.[^:#\\[\\.,]*$/;\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, not ) {\n\tif ( jQuery.isFunction( qualifier ) ) {\n\t\treturn jQuery.grep( elements, function( elem, i ) {\n\t\t\t/* jshint -W018 */\n\t\t\treturn !!qualifier.call( elem, i, elem ) !== not;\n\t\t} );\n\n\t}\n\n\tif ( qualifier.nodeType ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( elem === qualifier ) !== not;\n\t\t} );\n\n\t}\n\n\tif ( typeof qualifier === \"string\" ) {\n\t\tif ( risSimple.test( qualifier ) ) {\n\t\t\treturn jQuery.filter( qualifier, elements, not );\n\t\t}\n\n\t\tqualifier = jQuery.filter( qualifier, elements );\n\t}\n\n\treturn jQuery.grep( elements, function( elem ) {\n\t\treturn ( indexOf.call( qualifier, elem ) > -1 ) !== not;\n\t} );\n}\n\njQuery.filter = function( expr, elems, not ) {\n\tvar elem = elems[ 0 ];\n\n\tif ( not ) {\n\t\texpr = \":not(\" + expr + \")\";\n\t}\n\n\treturn elems.length === 1 && elem.nodeType === 1 ?\n\t\tjQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :\n\t\tjQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {\n\t\t\treturn elem.nodeType === 1;\n\t\t} ) );\n};\n\njQuery.fn.extend( {\n\tfind: function( selector ) {\n\t\tvar i,\n\t\t\tlen = this.length,\n\t\t\tret = [],\n\t\t\tself = this;\n\n\t\tif ( typeof selector !== \"string\" ) {\n\t\t\treturn this.pushStack( jQuery( selector ).filter( function() {\n\t\t\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\t\t\tif ( jQuery.contains( self[ i ], this ) ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} ) );\n\t\t}\n\n\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\tjQuery.find( selector, self[ i ], ret );\n\t\t}\n\n\t\t// Needed because $( selector, context ) becomes $( context ).find( selector )\n\t\tret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );\n\t\tret.selector = this.selector ? this.selector + \" \" + selector : selector;\n\t\treturn ret;\n\t},\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], false ) );\n\t},\n\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], true ) );\n\t},\n\tis: function( selector ) {\n\t\treturn !!winnow(\n\t\t\tthis,\n\n\t\t\t// If this is a positional/relative selector, check membership in the returned set\n\t\t\t// so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n\t\t\ttypeof selector === \"string\" && rneedsContext.test( selector ) ?\n\t\t\t\tjQuery( selector ) :\n\t\t\t\tselector || [],\n\t\t\tfalse\n\t\t).length;\n\t}\n} );\n\n\n// Initialize a jQuery object\n\n\n// A central reference to the root jQuery(document)\nvar rootjQuery,\n\n\t// A simple way to check for HTML strings\n\t// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)\n\t// Strict HTML recognition (#11290: must start with <)\n\trquickExpr = /^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]*))$/,\n\n\tinit = jQuery.fn.init = function( selector, context, root ) {\n\t\tvar match, elem;\n\n\t\t// HANDLE: $(\"\"), $(null), $(undefined), $(false)\n\t\tif ( !selector ) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Method init() accepts an alternate rootjQuery\n\t\t// so migrate can support jQuery.sub (gh-2101)\n\t\troot = root || rootjQuery;\n\n\t\t// Handle HTML strings\n\t\tif ( typeof selector === \"string\" ) {\n\t\t\tif ( selector[ 0 ] === \"<\" &&\n\t\t\t\tselector[ selector.length - 1 ] === \">\" &&\n\t\t\t\tselector.length >= 3 ) {\n\n\t\t\t\t// Assume that strings that start and end with <> are HTML and skip the regex check\n\t\t\t\tmatch = [ null, selector, null ];\n\n\t\t\t} else {\n\t\t\t\tmatch = rquickExpr.exec( selector );\n\t\t\t}\n\n\t\t\t// Match html or make sure no context is specified for #id\n\t\t\tif ( match && ( match[ 1 ] || !context ) ) {\n\n\t\t\t\t// HANDLE: $(html) -> $(array)\n\t\t\t\tif ( match[ 1 ] ) {\n\t\t\t\t\tcontext = context instanceof jQuery ? context[ 0 ] : context;\n\n\t\t\t\t\t// Option to run scripts is true for back-compat\n\t\t\t\t\t// Intentionally let the error be thrown if parseHTML is not present\n\t\t\t\t\tjQuery.merge( this, jQuery.parseHTML(\n\t\t\t\t\t\tmatch[ 1 ],\n\t\t\t\t\t\tcontext && context.nodeType ? context.ownerDocument || context : document,\n\t\t\t\t\t\ttrue\n\t\t\t\t\t) );\n\n\t\t\t\t\t// HANDLE: $(html, props)\n\t\t\t\t\tif ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {\n\t\t\t\t\t\tfor ( match in context ) {\n\n\t\t\t\t\t\t\t// Properties of context are called as methods if possible\n\t\t\t\t\t\t\tif ( jQuery.isFunction( this[ match ] ) ) {\n\t\t\t\t\t\t\t\tthis[ match ]( context[ match ] );\n\n\t\t\t\t\t\t\t// ...and otherwise set as attributes\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.attr( match, context[ match ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this;\n\n\t\t\t\t// HANDLE: $(#id)\n\t\t\t\t} else {\n\t\t\t\t\telem = document.getElementById( match[ 2 ] );\n\n\t\t\t\t\t// Support: Blackberry 4.6\n\t\t\t\t\t// gEBID returns nodes no longer in the document (#6963)\n\t\t\t\t\tif ( elem && elem.parentNode ) {\n\n\t\t\t\t\t\t// Inject the element directly into the jQuery object\n\t\t\t\t\t\tthis.length = 1;\n\t\t\t\t\t\tthis[ 0 ] = elem;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.context = document;\n\t\t\t\t\tthis.selector = selector;\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\n\t\t\t// HANDLE: $(expr, $(...))\n\t\t\t} else if ( !context || context.jquery ) {\n\t\t\t\treturn ( context || root ).find( selector );\n\n\t\t\t// HANDLE: $(expr, context)\n\t\t\t// (which is just equivalent to: $(context).find(expr)\n\t\t\t} else {\n\t\t\t\treturn this.constructor( context ).find( selector );\n\t\t\t}\n\n\t\t// HANDLE: $(DOMElement)\n\t\t} else if ( selector.nodeType ) {\n\t\t\tthis.context = this[ 0 ] = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\n\n\t\t// HANDLE: $(function)\n\t\t// Shortcut for document ready\n\t\t} else if ( jQuery.isFunction( selector ) ) {\n\t\t\treturn root.ready !== undefined ?\n\t\t\t\troot.ready( selector ) :\n\n\t\t\t\t// Execute immediately if ready is not present\n\t\t\t\tselector( jQuery );\n\t\t}\n\n\t\tif ( selector.selector !== undefined ) {\n\t\t\tthis.selector = selector.selector;\n\t\t\tthis.context = selector.context;\n\t\t}\n\n\t\treturn jQuery.makeArray( selector, this );\n\t};\n\n// Give the init function the jQuery prototype for later instantiation\ninit.prototype = jQuery.fn;\n\n// Initialize central reference\nrootjQuery = jQuery( document );\n\n\nvar rparentsprev = /^(?:parents|prev(?:Until|All))/,\n\n\t// Methods guaranteed to produce a unique set when starting from a unique set\n\tguaranteedUnique = {\n\t\tchildren: true,\n\t\tcontents: true,\n\t\tnext: true,\n\t\tprev: true\n\t};\n\njQuery.fn.extend( {\n\thas: function( target ) {\n\t\tvar targets = jQuery( target, this ),\n\t\t\tl = targets.length;\n\n\t\treturn this.filter( function() {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tif ( jQuery.contains( this, targets[ i ] ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\tclosest: function( selectors, context ) {\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tmatched = [],\n\t\t\tpos = rneedsContext.test( selectors ) || typeof selectors !== \"string\" ?\n\t\t\t\tjQuery( selectors, context || this.context ) :\n\t\t\t\t0;\n\n\t\tfor ( ; i < l; i++ ) {\n\t\t\tfor ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {\n\n\t\t\t\t// Always skip document fragments\n\t\t\t\tif ( cur.nodeType < 11 && ( pos ?\n\t\t\t\t\tpos.index( cur ) > -1 :\n\n\t\t\t\t\t// Don't pass non-elements to Sizzle\n\t\t\t\t\tcur.nodeType === 1 &&\n\t\t\t\t\t\tjQuery.find.matchesSelector( cur, selectors ) ) ) {\n\n\t\t\t\t\tmatched.push( cur );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );\n\t},\n\n\t// Determine the position of an element within the set\n\tindex: function( elem ) {\n\n\t\t// No argument, return index in parent\n\t\tif ( !elem ) {\n\t\t\treturn ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;\n\t\t}\n\n\t\t// Index in selector\n\t\tif ( typeof elem === \"string\" ) {\n\t\t\treturn indexOf.call( jQuery( elem ), this[ 0 ] );\n\t\t}\n\n\t\t// Locate the position of the desired element\n\t\treturn indexOf.call( this,\n\n\t\t\t// If it receives a jQuery object, the first element is used\n\t\t\telem.jquery ? elem[ 0 ] : elem\n\t\t);\n\t},\n\n\tadd: function( selector, context ) {\n\t\treturn this.pushStack(\n\t\t\tjQuery.uniqueSort(\n\t\t\t\tjQuery.merge( this.get(), jQuery( selector, context ) )\n\t\t\t)\n\t\t);\n\t},\n\n\taddBack: function( selector ) {\n\t\treturn this.add( selector == null ?\n\t\t\tthis.prevObject : this.prevObject.filter( selector )\n\t\t);\n\t}\n} );\n\nfunction sibling( cur, dir ) {\n\twhile ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}\n\treturn cur;\n}\n\njQuery.each( {\n\tparent: function( elem ) {\n\t\tvar parent = elem.parentNode;\n\t\treturn parent && parent.nodeType !== 11 ? parent : null;\n\t},\n\tparents: function( elem ) {\n\t\treturn dir( elem, \"parentNode\" );\n\t},\n\tparentsUntil: function( elem, i, until ) {\n\t\treturn dir( elem, \"parentNode\", until );\n\t},\n\tnext: function( elem ) {\n\t\treturn sibling( elem, \"nextSibling\" );\n\t},\n\tprev: function( elem ) {\n\t\treturn sibling( elem, \"previousSibling\" );\n\t},\n\tnextAll: function( elem ) {\n\t\treturn dir( elem, \"nextSibling\" );\n\t},\n\tprevAll: function( elem ) {\n\t\treturn dir( elem, \"previousSibling\" );\n\t},\n\tnextUntil: function( elem, i, until ) {\n\t\treturn dir( elem, \"nextSibling\", until );\n\t},\n\tprevUntil: function( elem, i, until ) {\n\t\treturn dir( elem, \"previousSibling\", until );\n\t},\n\tsiblings: function( elem ) {\n\t\treturn siblings( ( elem.parentNode || {} ).firstChild, elem );\n\t},\n\tchildren: function( elem ) {\n\t\treturn siblings( elem.firstChild );\n\t},\n\tcontents: function( elem ) {\n\t\treturn elem.contentDocument || jQuery.merge( [], elem.childNodes );\n\t}\n}, function( name, fn ) {\n\tjQuery.fn[ name ] = function( until, selector ) {\n\t\tvar matched = jQuery.map( this, fn, until );\n\n\t\tif ( name.slice( -5 ) !== \"Until\" ) {\n\t\t\tselector = until;\n\t\t}\n\n\t\tif ( selector && typeof selector === \"string\" ) {\n\t\t\tmatched = jQuery.filter( selector, matched );\n\t\t}\n\n\t\tif ( this.length > 1 ) {\n\n\t\t\t// Remove duplicates\n\t\t\tif ( !guaranteedUnique[ name ] ) {\n\t\t\t\tjQuery.uniqueSort( matched );\n\t\t\t}\n\n\t\t\t// Reverse order for parents* and prev-derivatives\n\t\t\tif ( rparentsprev.test( name ) ) {\n\t\t\t\tmatched.reverse();\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched );\n\t};\n} );\nvar rnotwhite = ( /\\S+/g );\n\n\n\n// Convert String-formatted options into Object-formatted ones\nfunction createOptions( options ) {\n\tvar object = {};\n\tjQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {\n\t\tobject[ flag ] = true;\n\t} );\n\treturn object;\n}\n\n/*\n * Create a callback list using the following parameters:\n *\n *\toptions: an optional list of space-separated options that will change how\n *\t\t\tthe callback list behaves or a more traditional option object\n *\n * By default a callback list will act like an event callback list and can be\n * \"fired\" multiple times.\n *\n * Possible options:\n *\n *\tonce:\t\t\twill ensure the callback list can only be fired once (like a Deferred)\n *\n *\tmemory:\t\t\twill keep track of previous values and will call any callback added\n *\t\t\t\t\tafter the list has been fired right away with the latest \"memorized\"\n *\t\t\t\t\tvalues (like a Deferred)\n *\n *\tunique:\t\t\twill ensure a callback can only be added once (no duplicate in the list)\n *\n *\tstopOnFalse:\tinterrupt callings when a callback returns false\n *\n */\njQuery.Callbacks = function( options ) {\n\n\t// Convert options from String-formatted to Object-formatted if needed\n\t// (we check in cache first)\n\toptions = typeof options === \"string\" ?\n\t\tcreateOptions( options ) :\n\t\tjQuery.extend( {}, options );\n\n\tvar // Flag to know if list is currently firing\n\t\tfiring,\n\n\t\t// Last fire value for non-forgettable lists\n\t\tmemory,\n\n\t\t// Flag to know if list was already fired\n\t\tfired,\n\n\t\t// Flag to prevent firing\n\t\tlocked,\n\n\t\t// Actual callback list\n\t\tlist = [],\n\n\t\t// Queue of execution data for repeatable lists\n\t\tqueue = [],\n\n\t\t// Index of currently firing callback (modified by add/remove as needed)\n\t\tfiringIndex = -1,\n\n\t\t// Fire callbacks\n\t\tfire = function() {\n\n\t\t\t// Enforce single-firing\n\t\t\tlocked = options.once;\n\n\t\t\t// Execute callbacks for all pending executions,\n\t\t\t// respecting firingIndex overrides and runtime changes\n\t\t\tfired = firing = true;\n\t\t\tfor ( ; queue.length; firingIndex = -1 ) {\n\t\t\t\tmemory = queue.shift();\n\t\t\t\twhile ( ++firingIndex < list.length ) {\n\n\t\t\t\t\t// Run callback and check for early termination\n\t\t\t\t\tif ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&\n\t\t\t\t\t\toptions.stopOnFalse ) {\n\n\t\t\t\t\t\t// Jump to end and forget the data so .add doesn't re-fire\n\t\t\t\t\t\tfiringIndex = list.length;\n\t\t\t\t\t\tmemory = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Forget the data if we're done with it\n\t\t\tif ( !options.memory ) {\n\t\t\t\tmemory = false;\n\t\t\t}\n\n\t\t\tfiring = false;\n\n\t\t\t// Clean up if we're done firing for good\n\t\t\tif ( locked ) {\n\n\t\t\t\t// Keep an empty list if we have data for future add calls\n\t\t\t\tif ( memory ) {\n\t\t\t\t\tlist = [];\n\n\t\t\t\t// Otherwise, this object is spent\n\t\t\t\t} else {\n\t\t\t\t\tlist = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t// Actual Callbacks object\n\t\tself = {\n\n\t\t\t// Add a callback or a collection of callbacks to the list\n\t\t\tadd: function() {\n\t\t\t\tif ( list ) {\n\n\t\t\t\t\t// If we have memory from a past run, we should fire after adding\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfiringIndex = list.length - 1;\n\t\t\t\t\t\tqueue.push( memory );\n\t\t\t\t\t}\n\n\t\t\t\t\t( function add( args ) {\n\t\t\t\t\t\tjQuery.each( args, function( _, arg ) {\n\t\t\t\t\t\t\tif ( jQuery.isFunction( arg ) ) {\n\t\t\t\t\t\t\t\tif ( !options.unique || !self.has( arg ) ) {\n\t\t\t\t\t\t\t\t\tlist.push( arg );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if ( arg && arg.length && jQuery.type( arg ) !== \"string\" ) {\n\n\t\t\t\t\t\t\t\t// Inspect recursively\n\t\t\t\t\t\t\t\tadd( arg );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t} )( arguments );\n\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Remove a callback from the list\n\t\t\tremove: function() {\n\t\t\t\tjQuery.each( arguments, function( _, arg ) {\n\t\t\t\t\tvar index;\n\t\t\t\t\twhile ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {\n\t\t\t\t\t\tlist.splice( index, 1 );\n\n\t\t\t\t\t\t// Handle firing indexes\n\t\t\t\t\t\tif ( index <= firingIndex ) {\n\t\t\t\t\t\t\tfiringIndex--;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Check if a given callback is in the list.\n\t\t\t// If no argument is given, return whether or not list has callbacks attached.\n\t\t\thas: function( fn ) {\n\t\t\t\treturn fn ?\n\t\t\t\t\tjQuery.inArray( fn, list ) > -1 :\n\t\t\t\t\tlist.length > 0;\n\t\t\t},\n\n\t\t\t// Remove all callbacks from the list\n\t\t\tempty: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\tlist = [];\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Disable .fire and .add\n\t\t\t// Abort any current/pending executions\n\t\t\t// Clear all callbacks and values\n\t\t\tdisable: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tlist = memory = \"\";\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tdisabled: function() {\n\t\t\t\treturn !list;\n\t\t\t},\n\n\t\t\t// Disable .fire\n\t\t\t// Also disable .add unless we have memory (since it would have no effect)\n\t\t\t// Abort any pending executions\n\t\t\tlock: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tif ( !memory ) {\n\t\t\t\t\tlist = memory = \"\";\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tlocked: function() {\n\t\t\t\treturn !!locked;\n\t\t\t},\n\n\t\t\t// Call all callbacks with the given context and arguments\n\t\t\tfireWith: function( context, args ) {\n\t\t\t\tif ( !locked ) {\n\t\t\t\t\targs = args || [];\n\t\t\t\t\targs = [ context, args.slice ? args.slice() : args ];\n\t\t\t\t\tqueue.push( args );\n\t\t\t\t\tif ( !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Call all the callbacks with the given arguments\n\t\t\tfire: function() {\n\t\t\t\tself.fireWith( this, arguments );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// To know if the callbacks have already been called at least once\n\t\t\tfired: function() {\n\t\t\t\treturn !!fired;\n\t\t\t}\n\t\t};\n\n\treturn self;\n};\n\n\njQuery.extend( {\n\n\tDeferred: function( func ) {\n\t\tvar tuples = [\n\n\t\t\t\t// action, add listener, listener list, final state\n\t\t\t\t[ \"resolve\", \"done\", jQuery.Callbacks( \"once memory\" ), \"resolved\" ],\n\t\t\t\t[ \"reject\", \"fail\", jQuery.Callbacks( \"once memory\" ), \"rejected\" ],\n\t\t\t\t[ \"notify\", \"progress\", jQuery.Callbacks( \"memory\" ) ]\n\t\t\t],\n\t\t\tstate = \"pending\",\n\t\t\tpromise = {\n\t\t\t\tstate: function() {\n\t\t\t\t\treturn state;\n\t\t\t\t},\n\t\t\t\talways: function() {\n\t\t\t\t\tdeferred.done( arguments ).fail( arguments );\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\t\t\t\tthen: function( /* fnDone, fnFail, fnProgress */ ) {\n\t\t\t\t\tvar fns = arguments;\n\t\t\t\t\treturn jQuery.Deferred( function( newDefer ) {\n\t\t\t\t\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\t\t\t\t\tvar fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];\n\n\t\t\t\t\t\t\t// deferred[ done | fail | progress ] for forwarding actions to newDefer\n\t\t\t\t\t\t\tdeferred[ tuple[ 1 ] ]( function() {\n\t\t\t\t\t\t\t\tvar returned = fn && fn.apply( this, arguments );\n\t\t\t\t\t\t\t\tif ( returned && jQuery.isFunction( returned.promise ) ) {\n\t\t\t\t\t\t\t\t\treturned.promise()\n\t\t\t\t\t\t\t\t\t\t.progress( newDefer.notify )\n\t\t\t\t\t\t\t\t\t\t.done( newDefer.resolve )\n\t\t\t\t\t\t\t\t\t\t.fail( newDefer.reject );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tnewDefer[ tuple[ 0 ] + \"With\" ](\n\t\t\t\t\t\t\t\t\t\tthis === promise ? newDefer.promise() : this,\n\t\t\t\t\t\t\t\t\t\tfn ? [ returned ] : arguments\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} );\n\t\t\t\t\t\tfns = null;\n\t\t\t\t\t} ).promise();\n\t\t\t\t},\n\n\t\t\t\t// Get a promise for this deferred\n\t\t\t\t// If obj is provided, the promise aspect is added to the object\n\t\t\t\tpromise: function( obj ) {\n\t\t\t\t\treturn obj != null ? jQuery.extend( obj, promise ) : promise;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdeferred = {};\n\n\t\t// Keep pipe for back-compat\n\t\tpromise.pipe = promise.then;\n\n\t\t// Add list-specific methods\n\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\tvar list = tuple[ 2 ],\n\t\t\t\tstateString = tuple[ 3 ];\n\n\t\t\t// promise[ done | fail | progress ] = list.add\n\t\t\tpromise[ tuple[ 1 ] ] = list.add;\n\n\t\t\t// Handle state\n\t\t\tif ( stateString ) {\n\t\t\t\tlist.add( function() {\n\n\t\t\t\t\t// state = [ resolved | rejected ]\n\t\t\t\t\tstate = stateString;\n\n\t\t\t\t// [ reject_list | resolve_list ].disable; progress_list.lock\n\t\t\t\t}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );\n\t\t\t}\n\n\t\t\t// deferred[ resolve | reject | notify ]\n\t\t\tdeferred[ tuple[ 0 ] ] = function() {\n\t\t\t\tdeferred[ tuple[ 0 ] + \"With\" ]( this === deferred ? promise : this, arguments );\n\t\t\t\treturn this;\n\t\t\t};\n\t\t\tdeferred[ tuple[ 0 ] + \"With\" ] = list.fireWith;\n\t\t} );\n\n\t\t// Make the deferred a promise\n\t\tpromise.promise( deferred );\n\n\t\t// Call given func if any\n\t\tif ( func ) {\n\t\t\tfunc.call( deferred, deferred );\n\t\t}\n\n\t\t// All done!\n\t\treturn deferred;\n\t},\n\n\t// Deferred helper\n\twhen: function( subordinate /* , ..., subordinateN */ ) {\n\t\tvar i = 0,\n\t\t\tresolveValues = slice.call( arguments ),\n\t\t\tlength = resolveValues.length,\n\n\t\t\t// the count of uncompleted subordinates\n\t\t\tremaining = length !== 1 ||\n\t\t\t\t( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,\n\n\t\t\t// the master Deferred.\n\t\t\t// If resolveValues consist of only a single Deferred, just use that.\n\t\t\tdeferred = remaining === 1 ? subordinate : jQuery.Deferred(),\n\n\t\t\t// Update function for both resolve and progress values\n\t\t\tupdateFunc = function( i, contexts, values ) {\n\t\t\t\treturn function( value ) {\n\t\t\t\t\tcontexts[ i ] = this;\n\t\t\t\t\tvalues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;\n\t\t\t\t\tif ( values === progressValues ) {\n\t\t\t\t\t\tdeferred.notifyWith( contexts, values );\n\t\t\t\t\t} else if ( !( --remaining ) ) {\n\t\t\t\t\t\tdeferred.resolveWith( contexts, values );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t},\n\n\t\t\tprogressValues, progressContexts, resolveContexts;\n\n\t\t// Add listeners to Deferred subordinates; treat others as resolved\n\t\tif ( length > 1 ) {\n\t\t\tprogressValues = new Array( length );\n\t\t\tprogressContexts = new Array( length );\n\t\t\tresolveContexts = new Array( length );\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {\n\t\t\t\t\tresolveValues[ i ].promise()\n\t\t\t\t\t\t.progress( updateFunc( i, progressContexts, progressValues ) )\n\t\t\t\t\t\t.done( updateFunc( i, resolveContexts, resolveValues ) )\n\t\t\t\t\t\t.fail( deferred.reject );\n\t\t\t\t} else {\n\t\t\t\t\t--remaining;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// If we're not waiting on anything, resolve the master\n\t\tif ( !remaining ) {\n\t\t\tdeferred.resolveWith( resolveContexts, resolveValues );\n\t\t}\n\n\t\treturn deferred.promise();\n\t}\n} );\n\n\n// The deferred used on DOM ready\nvar readyList;\n\njQuery.fn.ready = function( fn ) {\n\n\t// Add the callback\n\tjQuery.ready.promise().done( fn );\n\n\treturn this;\n};\n\njQuery.extend( {\n\n\t// Is the DOM ready to be used? Set to true once it occurs.\n\tisReady: false,\n\n\t// A counter to track how many items to wait for before\n\t// the ready event fires. See #6781\n\treadyWait: 1,\n\n\t// Hold (or release) the ready event\n\tholdReady: function( hold ) {\n\t\tif ( hold ) {\n\t\t\tjQuery.readyWait++;\n\t\t} else {\n\t\t\tjQuery.ready( true );\n\t\t}\n\t},\n\n\t// Handle when the DOM is ready\n\tready: function( wait ) {\n\n\t\t// Abort if there are pending holds or we're already ready\n\t\tif ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Remember that the DOM is ready\n\t\tjQuery.isReady = true;\n\n\t\t// If a normal DOM Ready event fired, decrement, and wait if need be\n\t\tif ( wait !== true && --jQuery.readyWait > 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If there are functions bound, to execute\n\t\treadyList.resolveWith( document, [ jQuery ] );\n\n\t\t// Trigger any bound ready events\n\t\tif ( jQuery.fn.triggerHandler ) {\n\t\t\tjQuery( document ).triggerHandler( \"ready\" );\n\t\t\tjQuery( document ).off( \"ready\" );\n\t\t}\n\t}\n} );\n\n/**\n * The ready event handler and self cleanup method\n */\nfunction completed() {\n\tdocument.removeEventListener( \"DOMContentLoaded\", completed );\n\twindow.removeEventListener( \"load\", completed );\n\tjQuery.ready();\n}\n\njQuery.ready.promise = function( obj ) {\n\tif ( !readyList ) {\n\n\t\treadyList = jQuery.Deferred();\n\n\t\t// Catch cases where $(document).ready() is called\n\t\t// after the browser event has already occurred.\n\t\t// Support: IE9-10 only\n\t\t// Older IE sometimes signals \"interactive\" too soon\n\t\tif ( document.readyState === \"complete\" ||\n\t\t\t( document.readyState !== \"loading\" && !document.documentElement.doScroll ) ) {\n\n\t\t\t// Handle it asynchronously to allow scripts the opportunity to delay ready\n\t\t\twindow.setTimeout( jQuery.ready );\n\n\t\t} else {\n\n\t\t\t// Use the handy event callback\n\t\t\tdocument.addEventListener( \"DOMContentLoaded\", completed );\n\n\t\t\t// A fallback to window.onload, that will always work\n\t\t\twindow.addEventListener( \"load\", completed );\n\t\t}\n\t}\n\treturn readyList.promise( obj );\n};\n\n// Kick off the DOM ready check even if the user does not\njQuery.ready.promise();\n\n\n\n\n// Multifunctional method to get and set values of a collection\n// The value/s can optionally be executed if it's a function\nvar access = function( elems, fn, key, value, chainable, emptyGet, raw ) {\n\tvar i = 0,\n\t\tlen = elems.length,\n\t\tbulk = key == null;\n\n\t// Sets many values\n\tif ( jQuery.type( key ) === \"object\" ) {\n\t\tchainable = true;\n\t\tfor ( i in key ) {\n\t\t\taccess( elems, fn, i, key[ i ], true, emptyGet, raw );\n\t\t}\n\n\t// Sets one value\n\t} else if ( value !== undefined ) {\n\t\tchainable = true;\n\n\t\tif ( !jQuery.isFunction( value ) ) {\n\t\t\traw = true;\n\t\t}\n\n\t\tif ( bulk ) {\n\n\t\t\t// Bulk operations run against the entire set\n\t\t\tif ( raw ) {\n\t\t\t\tfn.call( elems, value );\n\t\t\t\tfn = null;\n\n\t\t\t// ...except when executing function values\n\t\t\t} else {\n\t\t\t\tbulk = fn;\n\t\t\t\tfn = function( elem, key, value ) {\n\t\t\t\t\treturn bulk.call( jQuery( elem ), value );\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif ( fn ) {\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\tfn(\n\t\t\t\t\telems[ i ], key, raw ?\n\t\t\t\t\tvalue :\n\t\t\t\t\tvalue.call( elems[ i ], i, fn( elems[ i ], key ) )\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn chainable ?\n\t\telems :\n\n\t\t// Gets\n\t\tbulk ?\n\t\t\tfn.call( elems ) :\n\t\t\tlen ? fn( elems[ 0 ], key ) : emptyGet;\n};\nvar acceptData = function( owner ) {\n\n\t// Accepts only:\n\t//  - Node\n\t//    - Node.ELEMENT_NODE\n\t//    - Node.DOCUMENT_NODE\n\t//  - Object\n\t//    - Any\n\t/* jshint -W018 */\n\treturn owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );\n};\n\n\n\n\nfunction Data() {\n\tthis.expando = jQuery.expando + Data.uid++;\n}\n\nData.uid = 1;\n\nData.prototype = {\n\n\tregister: function( owner, initial ) {\n\t\tvar value = initial || {};\n\n\t\t// If it is a node unlikely to be stringify-ed or looped over\n\t\t// use plain assignment\n\t\tif ( owner.nodeType ) {\n\t\t\towner[ this.expando ] = value;\n\n\t\t// Otherwise secure it in a non-enumerable, non-writable property\n\t\t// configurability must be true to allow the property to be\n\t\t// deleted with the delete operator\n\t\t} else {\n\t\t\tObject.defineProperty( owner, this.expando, {\n\t\t\t\tvalue: value,\n\t\t\t\twritable: true,\n\t\t\t\tconfigurable: true\n\t\t\t} );\n\t\t}\n\t\treturn owner[ this.expando ];\n\t},\n\tcache: function( owner ) {\n\n\t\t// We can accept data for non-element nodes in modern browsers,\n\t\t// but we should not, see #8335.\n\t\t// Always return an empty object.\n\t\tif ( !acceptData( owner ) ) {\n\t\t\treturn {};\n\t\t}\n\n\t\t// Check if the owner object already has a cache\n\t\tvar value = owner[ this.expando ];\n\n\t\t// If not, create one\n\t\tif ( !value ) {\n\t\t\tvalue = {};\n\n\t\t\t// We can accept data for non-element nodes in modern browsers,\n\t\t\t// but we should not, see #8335.\n\t\t\t// Always return an empty object.\n\t\t\tif ( acceptData( owner ) ) {\n\n\t\t\t\t// If it is a node unlikely to be stringify-ed or looped over\n\t\t\t\t// use plain assignment\n\t\t\t\tif ( owner.nodeType ) {\n\t\t\t\t\towner[ this.expando ] = value;\n\n\t\t\t\t// Otherwise secure it in a non-enumerable property\n\t\t\t\t// configurable must be true to allow the property to be\n\t\t\t\t// deleted when data is removed\n\t\t\t\t} else {\n\t\t\t\t\tObject.defineProperty( owner, this.expando, {\n\t\t\t\t\t\tvalue: value,\n\t\t\t\t\t\tconfigurable: true\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn value;\n\t},\n\tset: function( owner, data, value ) {\n\t\tvar prop,\n\t\t\tcache = this.cache( owner );\n\n\t\t// Handle: [ owner, key, value ] args\n\t\tif ( typeof data === \"string\" ) {\n\t\t\tcache[ data ] = value;\n\n\t\t// Handle: [ owner, { properties } ] args\n\t\t} else {\n\n\t\t\t// Copy the properties one-by-one to the cache object\n\t\t\tfor ( prop in data ) {\n\t\t\t\tcache[ prop ] = data[ prop ];\n\t\t\t}\n\t\t}\n\t\treturn cache;\n\t},\n\tget: function( owner, key ) {\n\t\treturn key === undefined ?\n\t\t\tthis.cache( owner ) :\n\t\t\towner[ this.expando ] && owner[ this.expando ][ key ];\n\t},\n\taccess: function( owner, key, value ) {\n\t\tvar stored;\n\n\t\t// In cases where either:\n\t\t//\n\t\t//   1. No key was specified\n\t\t//   2. A string key was specified, but no value provided\n\t\t//\n\t\t// Take the \"read\" path and allow the get method to determine\n\t\t// which value to return, respectively either:\n\t\t//\n\t\t//   1. The entire cache object\n\t\t//   2. The data stored at the key\n\t\t//\n\t\tif ( key === undefined ||\n\t\t\t\t( ( key && typeof key === \"string\" ) && value === undefined ) ) {\n\n\t\t\tstored = this.get( owner, key );\n\n\t\t\treturn stored !== undefined ?\n\t\t\t\tstored : this.get( owner, jQuery.camelCase( key ) );\n\t\t}\n\n\t\t// When the key is not a string, or both a key and value\n\t\t// are specified, set or extend (existing objects) with either:\n\t\t//\n\t\t//   1. An object of properties\n\t\t//   2. A key and value\n\t\t//\n\t\tthis.set( owner, key, value );\n\n\t\t// Since the \"set\" path can have two possible entry points\n\t\t// return the expected data based on which path was taken[*]\n\t\treturn value !== undefined ? value : key;\n\t},\n\tremove: function( owner, key ) {\n\t\tvar i, name, camel,\n\t\t\tcache = owner[ this.expando ];\n\n\t\tif ( cache === undefined ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( key === undefined ) {\n\t\t\tthis.register( owner );\n\n\t\t} else {\n\n\t\t\t// Support array or space separated string of keys\n\t\t\tif ( jQuery.isArray( key ) ) {\n\n\t\t\t\t// If \"name\" is an array of keys...\n\t\t\t\t// When data is initially created, via (\"key\", \"val\") signature,\n\t\t\t\t// keys will be converted to camelCase.\n\t\t\t\t// Since there is no way to tell _how_ a key was added, remove\n\t\t\t\t// both plain key and camelCase key. #12786\n\t\t\t\t// This will only penalize the array argument path.\n\t\t\t\tname = key.concat( key.map( jQuery.camelCase ) );\n\t\t\t} else {\n\t\t\t\tcamel = jQuery.camelCase( key );\n\n\t\t\t\t// Try the string as a key before any manipulation\n\t\t\t\tif ( key in cache ) {\n\t\t\t\t\tname = [ key, camel ];\n\t\t\t\t} else {\n\n\t\t\t\t\t// If a key with the spaces exists, use it.\n\t\t\t\t\t// Otherwise, create an array by matching non-whitespace\n\t\t\t\t\tname = camel;\n\t\t\t\t\tname = name in cache ?\n\t\t\t\t\t\t[ name ] : ( name.match( rnotwhite ) || [] );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ti = name.length;\n\n\t\t\twhile ( i-- ) {\n\t\t\t\tdelete cache[ name[ i ] ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove the expando if there's no more data\n\t\tif ( key === undefined || jQuery.isEmptyObject( cache ) ) {\n\n\t\t\t// Support: Chrome <= 35-45+\n\t\t\t// Webkit & Blink performance suffers when deleting properties\n\t\t\t// from DOM nodes, so set to undefined instead\n\t\t\t// https://code.google.com/p/chromium/issues/detail?id=378607\n\t\t\tif ( owner.nodeType ) {\n\t\t\t\towner[ this.expando ] = undefined;\n\t\t\t} else {\n\t\t\t\tdelete owner[ this.expando ];\n\t\t\t}\n\t\t}\n\t},\n\thasData: function( owner ) {\n\t\tvar cache = owner[ this.expando ];\n\t\treturn cache !== undefined && !jQuery.isEmptyObject( cache );\n\t}\n};\nvar dataPriv = new Data();\n\nvar dataUser = new Data();\n\n\n\n//\tImplementation Summary\n//\n//\t1. Enforce API surface and semantic compatibility with 1.9.x branch\n//\t2. Improve the module's maintainability by reducing the storage\n//\t\tpaths to a single mechanism.\n//\t3. Use the same single mechanism to support \"private\" and \"user\" data.\n//\t4. _Never_ expose \"private\" data to user code (TODO: Drop _data, _removeData)\n//\t5. Avoid exposing implementation details on user objects (eg. expando properties)\n//\t6. Provide a clear path for implementation upgrade to WeakMap in 2014\n\nvar rbrace = /^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,\n\trmultiDash = /[A-Z]/g;\n\nfunction dataAttr( elem, key, data ) {\n\tvar name;\n\n\t// If nothing was found internally, try to fetch any\n\t// data from the HTML5 data-* attribute\n\tif ( data === undefined && elem.nodeType === 1 ) {\n\t\tname = \"data-\" + key.replace( rmultiDash, \"-$&\" ).toLowerCase();\n\t\tdata = elem.getAttribute( name );\n\n\t\tif ( typeof data === \"string\" ) {\n\t\t\ttry {\n\t\t\t\tdata = data === \"true\" ? true :\n\t\t\t\t\tdata === \"false\" ? false :\n\t\t\t\t\tdata === \"null\" ? null :\n\n\t\t\t\t\t// Only convert to a number if it doesn't change the string\n\t\t\t\t\t+data + \"\" === data ? +data :\n\t\t\t\t\trbrace.test( data ) ? jQuery.parseJSON( data ) :\n\t\t\t\t\tdata;\n\t\t\t} catch ( e ) {}\n\n\t\t\t// Make sure we set the data so it isn't changed later\n\t\t\tdataUser.set( elem, key, data );\n\t\t} else {\n\t\t\tdata = undefined;\n\t\t}\n\t}\n\treturn data;\n}\n\njQuery.extend( {\n\thasData: function( elem ) {\n\t\treturn dataUser.hasData( elem ) || dataPriv.hasData( elem );\n\t},\n\n\tdata: function( elem, name, data ) {\n\t\treturn dataUser.access( elem, name, data );\n\t},\n\n\tremoveData: function( elem, name ) {\n\t\tdataUser.remove( elem, name );\n\t},\n\n\t// TODO: Now that all calls to _data and _removeData have been replaced\n\t// with direct calls to dataPriv methods, these can be deprecated.\n\t_data: function( elem, name, data ) {\n\t\treturn dataPriv.access( elem, name, data );\n\t},\n\n\t_removeData: function( elem, name ) {\n\t\tdataPriv.remove( elem, name );\n\t}\n} );\n\njQuery.fn.extend( {\n\tdata: function( key, value ) {\n\t\tvar i, name, data,\n\t\t\telem = this[ 0 ],\n\t\t\tattrs = elem && elem.attributes;\n\n\t\t// Gets all values\n\t\tif ( key === undefined ) {\n\t\t\tif ( this.length ) {\n\t\t\t\tdata = dataUser.get( elem );\n\n\t\t\t\tif ( elem.nodeType === 1 && !dataPriv.get( elem, \"hasDataAttrs\" ) ) {\n\t\t\t\t\ti = attrs.length;\n\t\t\t\t\twhile ( i-- ) {\n\n\t\t\t\t\t\t// Support: IE11+\n\t\t\t\t\t\t// The attrs elements can be null (#14894)\n\t\t\t\t\t\tif ( attrs[ i ] ) {\n\t\t\t\t\t\t\tname = attrs[ i ].name;\n\t\t\t\t\t\t\tif ( name.indexOf( \"data-\" ) === 0 ) {\n\t\t\t\t\t\t\t\tname = jQuery.camelCase( name.slice( 5 ) );\n\t\t\t\t\t\t\t\tdataAttr( elem, name, data[ name ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdataPriv.set( elem, \"hasDataAttrs\", true );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn data;\n\t\t}\n\n\t\t// Sets multiple values\n\t\tif ( typeof key === \"object\" ) {\n\t\t\treturn this.each( function() {\n\t\t\t\tdataUser.set( this, key );\n\t\t\t} );\n\t\t}\n\n\t\treturn access( this, function( value ) {\n\t\t\tvar data, camelKey;\n\n\t\t\t// The calling jQuery object (element matches) is not empty\n\t\t\t// (and therefore has an element appears at this[ 0 ]) and the\n\t\t\t// `value` parameter was not undefined. An empty jQuery object\n\t\t\t// will result in `undefined` for elem = this[ 0 ] which will\n\t\t\t// throw an exception if an attempt to read a data cache is made.\n\t\t\tif ( elem && value === undefined ) {\n\n\t\t\t\t// Attempt to get data from the cache\n\t\t\t\t// with the key as-is\n\t\t\t\tdata = dataUser.get( elem, key ) ||\n\n\t\t\t\t\t// Try to find dashed key if it exists (gh-2779)\n\t\t\t\t\t// This is for 2.2.x only\n\t\t\t\t\tdataUser.get( elem, key.replace( rmultiDash, \"-$&\" ).toLowerCase() );\n\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\tcamelKey = jQuery.camelCase( key );\n\n\t\t\t\t// Attempt to get data from the cache\n\t\t\t\t// with the key camelized\n\t\t\t\tdata = dataUser.get( elem, camelKey );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// Attempt to \"discover\" the data in\n\t\t\t\t// HTML5 custom data-* attrs\n\t\t\t\tdata = dataAttr( elem, camelKey, undefined );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// We tried really hard, but the data doesn't exist.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Set the data...\n\t\t\tcamelKey = jQuery.camelCase( key );\n\t\t\tthis.each( function() {\n\n\t\t\t\t// First, attempt to store a copy or reference of any\n\t\t\t\t// data that might've been store with a camelCased key.\n\t\t\t\tvar data = dataUser.get( this, camelKey );\n\n\t\t\t\t// For HTML5 data-* attribute interop, we have to\n\t\t\t\t// store property names with dashes in a camelCase form.\n\t\t\t\t// This might not apply to all properties...*\n\t\t\t\tdataUser.set( this, camelKey, value );\n\n\t\t\t\t// *... In the case of properties that might _actually_\n\t\t\t\t// have dashes, we need to also store a copy of that\n\t\t\t\t// unchanged property.\n\t\t\t\tif ( key.indexOf( \"-\" ) > -1 && data !== undefined ) {\n\t\t\t\t\tdataUser.set( this, key, value );\n\t\t\t\t}\n\t\t\t} );\n\t\t}, null, value, arguments.length > 1, null, true );\n\t},\n\n\tremoveData: function( key ) {\n\t\treturn this.each( function() {\n\t\t\tdataUser.remove( this, key );\n\t\t} );\n\t}\n} );\n\n\njQuery.extend( {\n\tqueue: function( elem, type, data ) {\n\t\tvar queue;\n\n\t\tif ( elem ) {\n\t\t\ttype = ( type || \"fx\" ) + \"queue\";\n\t\t\tqueue = dataPriv.get( elem, type );\n\n\t\t\t// Speed up dequeue by getting out quickly if this is just a lookup\n\t\t\tif ( data ) {\n\t\t\t\tif ( !queue || jQuery.isArray( data ) ) {\n\t\t\t\t\tqueue = dataPriv.access( elem, type, jQuery.makeArray( data ) );\n\t\t\t\t} else {\n\t\t\t\t\tqueue.push( data );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn queue || [];\n\t\t}\n\t},\n\n\tdequeue: function( elem, type ) {\n\t\ttype = type || \"fx\";\n\n\t\tvar queue = jQuery.queue( elem, type ),\n\t\t\tstartLength = queue.length,\n\t\t\tfn = queue.shift(),\n\t\t\thooks = jQuery._queueHooks( elem, type ),\n\t\t\tnext = function() {\n\t\t\t\tjQuery.dequeue( elem, type );\n\t\t\t};\n\n\t\t// If the fx queue is dequeued, always remove the progress sentinel\n\t\tif ( fn === \"inprogress\" ) {\n\t\t\tfn = queue.shift();\n\t\t\tstartLength--;\n\t\t}\n\n\t\tif ( fn ) {\n\n\t\t\t// Add a progress sentinel to prevent the fx queue from being\n\t\t\t// automatically dequeued\n\t\t\tif ( type === \"fx\" ) {\n\t\t\t\tqueue.unshift( \"inprogress\" );\n\t\t\t}\n\n\t\t\t// Clear up the last queue stop function\n\t\t\tdelete hooks.stop;\n\t\t\tfn.call( elem, next, hooks );\n\t\t}\n\n\t\tif ( !startLength && hooks ) {\n\t\t\thooks.empty.fire();\n\t\t}\n\t},\n\n\t// Not public - generate a queueHooks object, or return the current one\n\t_queueHooks: function( elem, type ) {\n\t\tvar key = type + \"queueHooks\";\n\t\treturn dataPriv.get( elem, key ) || dataPriv.access( elem, key, {\n\t\t\tempty: jQuery.Callbacks( \"once memory\" ).add( function() {\n\t\t\t\tdataPriv.remove( elem, [ type + \"queue\", key ] );\n\t\t\t} )\n\t\t} );\n\t}\n} );\n\njQuery.fn.extend( {\n\tqueue: function( type, data ) {\n\t\tvar setter = 2;\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tdata = type;\n\t\t\ttype = \"fx\";\n\t\t\tsetter--;\n\t\t}\n\n\t\tif ( arguments.length < setter ) {\n\t\t\treturn jQuery.queue( this[ 0 ], type );\n\t\t}\n\n\t\treturn data === undefined ?\n\t\t\tthis :\n\t\t\tthis.each( function() {\n\t\t\t\tvar queue = jQuery.queue( this, type, data );\n\n\t\t\t\t// Ensure a hooks for this queue\n\t\t\t\tjQuery._queueHooks( this, type );\n\n\t\t\t\tif ( type === \"fx\" && queue[ 0 ] !== \"inprogress\" ) {\n\t\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t\t}\n\t\t\t} );\n\t},\n\tdequeue: function( type ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.dequeue( this, type );\n\t\t} );\n\t},\n\tclearQueue: function( type ) {\n\t\treturn this.queue( type || \"fx\", [] );\n\t},\n\n\t// Get a promise resolved when queues of a certain type\n\t// are emptied (fx is the type by default)\n\tpromise: function( type, obj ) {\n\t\tvar tmp,\n\t\t\tcount = 1,\n\t\t\tdefer = jQuery.Deferred(),\n\t\t\telements = this,\n\t\t\ti = this.length,\n\t\t\tresolve = function() {\n\t\t\t\tif ( !( --count ) ) {\n\t\t\t\t\tdefer.resolveWith( elements, [ elements ] );\n\t\t\t\t}\n\t\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tobj = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\ttype = type || \"fx\";\n\n\t\twhile ( i-- ) {\n\t\t\ttmp = dataPriv.get( elements[ i ], type + \"queueHooks\" );\n\t\t\tif ( tmp && tmp.empty ) {\n\t\t\t\tcount++;\n\t\t\t\ttmp.empty.add( resolve );\n\t\t\t}\n\t\t}\n\t\tresolve();\n\t\treturn defer.promise( obj );\n\t}\n} );\nvar pnum = ( /[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/ ).source;\n\nvar rcssNum = new RegExp( \"^(?:([+-])=|)(\" + pnum + \")([a-z%]*)$\", \"i\" );\n\n\nvar cssExpand = [ \"Top\", \"Right\", \"Bottom\", \"Left\" ];\n\nvar isHidden = function( elem, el ) {\n\n\t\t// isHidden might be called from jQuery#filter function;\n\t\t// in that case, element will be second argument\n\t\telem = el || elem;\n\t\treturn jQuery.css( elem, \"display\" ) === \"none\" ||\n\t\t\t!jQuery.contains( elem.ownerDocument, elem );\n\t};\n\n\n\nfunction adjustCSS( elem, prop, valueParts, tween ) {\n\tvar adjusted,\n\t\tscale = 1,\n\t\tmaxIterations = 20,\n\t\tcurrentValue = tween ?\n\t\t\tfunction() { return tween.cur(); } :\n\t\t\tfunction() { return jQuery.css( elem, prop, \"\" ); },\n\t\tinitial = currentValue(),\n\t\tunit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" ),\n\n\t\t// Starting value computation is required for potential unit mismatches\n\t\tinitialInUnit = ( jQuery.cssNumber[ prop ] || unit !== \"px\" && +initial ) &&\n\t\t\trcssNum.exec( jQuery.css( elem, prop ) );\n\n\tif ( initialInUnit && initialInUnit[ 3 ] !== unit ) {\n\n\t\t// Trust units reported by jQuery.css\n\t\tunit = unit || initialInUnit[ 3 ];\n\n\t\t// Make sure we update the tween properties later on\n\t\tvalueParts = valueParts || [];\n\n\t\t// Iteratively approximate from a nonzero starting point\n\t\tinitialInUnit = +initial || 1;\n\n\t\tdo {\n\n\t\t\t// If previous iteration zeroed out, double until we get *something*.\n\t\t\t// Use string for doubling so we don't accidentally see scale as unchanged below\n\t\t\tscale = scale || \".5\";\n\n\t\t\t// Adjust and apply\n\t\t\tinitialInUnit = initialInUnit / scale;\n\t\t\tjQuery.style( elem, prop, initialInUnit + unit );\n\n\t\t// Update scale, tolerating zero or NaN from tween.cur()\n\t\t// Break the loop if scale is unchanged or perfect, or if we've just had enough.\n\t\t} while (\n\t\t\tscale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations\n\t\t);\n\t}\n\n\tif ( valueParts ) {\n\t\tinitialInUnit = +initialInUnit || +initial || 0;\n\n\t\t// Apply relative offset (+=/-=) if specified\n\t\tadjusted = valueParts[ 1 ] ?\n\t\t\tinitialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :\n\t\t\t+valueParts[ 2 ];\n\t\tif ( tween ) {\n\t\t\ttween.unit = unit;\n\t\t\ttween.start = initialInUnit;\n\t\t\ttween.end = adjusted;\n\t\t}\n\t}\n\treturn adjusted;\n}\nvar rcheckableType = ( /^(?:checkbox|radio)$/i );\n\nvar rtagName = ( /<([\\w:-]+)/ );\n\nvar rscriptType = ( /^$|\\/(?:java|ecma)script/i );\n\n\n\n// We have to close these tags to support XHTML (#13200)\nvar wrapMap = {\n\n\t// Support: IE9\n\toption: [ 1, \"<select multiple='multiple'>\", \"</select>\" ],\n\n\t// XHTML parsers do not magically insert elements in the\n\t// same way that tag soup parsers do. So we cannot shorten\n\t// this by omitting <tbody> or other required elements.\n\tthead: [ 1, \"<table>\", \"</table>\" ],\n\tcol: [ 2, \"<table><colgroup>\", \"</colgroup></table>\" ],\n\ttr: [ 2, \"<table><tbody>\", \"</tbody></table>\" ],\n\ttd: [ 3, \"<table><tbody><tr>\", \"</tr></tbody></table>\" ],\n\n\t_default: [ 0, \"\", \"\" ]\n};\n\n// Support: IE9\nwrapMap.optgroup = wrapMap.option;\n\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\n\nfunction getAll( context, tag ) {\n\n\t// Support: IE9-11+\n\t// Use typeof to avoid zero-argument method invocation on host objects (#15151)\n\tvar ret = typeof context.getElementsByTagName !== \"undefined\" ?\n\t\t\tcontext.getElementsByTagName( tag || \"*\" ) :\n\t\t\ttypeof context.querySelectorAll !== \"undefined\" ?\n\t\t\t\tcontext.querySelectorAll( tag || \"*\" ) :\n\t\t\t[];\n\n\treturn tag === undefined || tag && jQuery.nodeName( context, tag ) ?\n\t\tjQuery.merge( [ context ], ret ) :\n\t\tret;\n}\n\n\n// Mark scripts as having already been evaluated\nfunction setGlobalEval( elems, refElements ) {\n\tvar i = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\tdataPriv.set(\n\t\t\telems[ i ],\n\t\t\t\"globalEval\",\n\t\t\t!refElements || dataPriv.get( refElements[ i ], \"globalEval\" )\n\t\t);\n\t}\n}\n\n\nvar rhtml = /<|&#?\\w+;/;\n\nfunction buildFragment( elems, context, scripts, selection, ignored ) {\n\tvar elem, tmp, tag, wrap, contains, j,\n\t\tfragment = context.createDocumentFragment(),\n\t\tnodes = [],\n\t\ti = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\telem = elems[ i ];\n\n\t\tif ( elem || elem === 0 ) {\n\n\t\t\t// Add nodes directly\n\t\t\tif ( jQuery.type( elem ) === \"object\" ) {\n\n\t\t\t\t// Support: Android<4.1, PhantomJS<2\n\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\tjQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );\n\n\t\t\t// Convert non-html into a text node\n\t\t\t} else if ( !rhtml.test( elem ) ) {\n\t\t\t\tnodes.push( context.createTextNode( elem ) );\n\n\t\t\t// Convert html into DOM nodes\n\t\t\t} else {\n\t\t\t\ttmp = tmp || fragment.appendChild( context.createElement( \"div\" ) );\n\n\t\t\t\t// Deserialize a standard representation\n\t\t\t\ttag = ( rtagName.exec( elem ) || [ \"\", \"\" ] )[ 1 ].toLowerCase();\n\t\t\t\twrap = wrapMap[ tag ] || wrapMap._default;\n\t\t\t\ttmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];\n\n\t\t\t\t// Descend through wrappers to the right content\n\t\t\t\tj = wrap[ 0 ];\n\t\t\t\twhile ( j-- ) {\n\t\t\t\t\ttmp = tmp.lastChild;\n\t\t\t\t}\n\n\t\t\t\t// Support: Android<4.1, PhantomJS<2\n\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\tjQuery.merge( nodes, tmp.childNodes );\n\n\t\t\t\t// Remember the top-level container\n\t\t\t\ttmp = fragment.firstChild;\n\n\t\t\t\t// Ensure the created nodes are orphaned (#12392)\n\t\t\t\ttmp.textContent = \"\";\n\t\t\t}\n\t\t}\n\t}\n\n\t// Remove wrapper from fragment\n\tfragment.textContent = \"\";\n\n\ti = 0;\n\twhile ( ( elem = nodes[ i++ ] ) ) {\n\n\t\t// Skip elements already in the context collection (trac-4087)\n\t\tif ( selection && jQuery.inArray( elem, selection ) > -1 ) {\n\t\t\tif ( ignored ) {\n\t\t\t\tignored.push( elem );\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tcontains = jQuery.contains( elem.ownerDocument, elem );\n\n\t\t// Append to fragment\n\t\ttmp = getAll( fragment.appendChild( elem ), \"script\" );\n\n\t\t// Preserve script evaluation history\n\t\tif ( contains ) {\n\t\t\tsetGlobalEval( tmp );\n\t\t}\n\n\t\t// Capture executables\n\t\tif ( scripts ) {\n\t\t\tj = 0;\n\t\t\twhile ( ( elem = tmp[ j++ ] ) ) {\n\t\t\t\tif ( rscriptType.test( elem.type || \"\" ) ) {\n\t\t\t\t\tscripts.push( elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fragment;\n}\n\n\n( function() {\n\tvar fragment = document.createDocumentFragment(),\n\t\tdiv = fragment.appendChild( document.createElement( \"div\" ) ),\n\t\tinput = document.createElement( \"input\" );\n\n\t// Support: Android 4.0-4.3, Safari<=5.1\n\t// Check state lost if the name is set (#11217)\n\t// Support: Windows Web Apps (WWA)\n\t// `name` and `type` must use .setAttribute for WWA (#14901)\n\tinput.setAttribute( \"type\", \"radio\" );\n\tinput.setAttribute( \"checked\", \"checked\" );\n\tinput.setAttribute( \"name\", \"t\" );\n\n\tdiv.appendChild( input );\n\n\t// Support: Safari<=5.1, Android<4.2\n\t// Older WebKit doesn't clone checked state correctly in fragments\n\tsupport.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;\n\n\t// Support: IE<=11+\n\t// Make sure textarea (and checkbox) defaultValue is properly cloned\n\tdiv.innerHTML = \"<textarea>x</textarea>\";\n\tsupport.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;\n} )();\n\n\nvar\n\trkeyEvent = /^key/,\n\trmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,\n\trtypenamespace = /^([^.]*)(?:\\.(.+)|)/;\n\nfunction returnTrue() {\n\treturn true;\n}\n\nfunction returnFalse() {\n\treturn false;\n}\n\n// Support: IE9\n// See #13393 for more info\nfunction safeActiveElement() {\n\ttry {\n\t\treturn document.activeElement;\n\t} catch ( err ) { }\n}\n\nfunction on( elem, types, selector, data, fn, one ) {\n\tvar origFn, type;\n\n\t// Types can be a map of types/handlers\n\tif ( typeof types === \"object\" ) {\n\n\t\t// ( types-Object, selector, data )\n\t\tif ( typeof selector !== \"string\" ) {\n\n\t\t\t// ( types-Object, data )\n\t\t\tdata = data || selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tfor ( type in types ) {\n\t\t\ton( elem, type, selector, data, types[ type ], one );\n\t\t}\n\t\treturn elem;\n\t}\n\n\tif ( data == null && fn == null ) {\n\n\t\t// ( types, fn )\n\t\tfn = selector;\n\t\tdata = selector = undefined;\n\t} else if ( fn == null ) {\n\t\tif ( typeof selector === \"string\" ) {\n\n\t\t\t// ( types, selector, fn )\n\t\t\tfn = data;\n\t\t\tdata = undefined;\n\t\t} else {\n\n\t\t\t// ( types, data, fn )\n\t\t\tfn = data;\n\t\t\tdata = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t}\n\tif ( fn === false ) {\n\t\tfn = returnFalse;\n\t} else if ( !fn ) {\n\t\treturn elem;\n\t}\n\n\tif ( one === 1 ) {\n\t\torigFn = fn;\n\t\tfn = function( event ) {\n\n\t\t\t// Can use an empty set, since event contains the info\n\t\t\tjQuery().off( event );\n\t\t\treturn origFn.apply( this, arguments );\n\t\t};\n\n\t\t// Use same guid so caller can remove using origFn\n\t\tfn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );\n\t}\n\treturn elem.each( function() {\n\t\tjQuery.event.add( this, types, fn, data, selector );\n\t} );\n}\n\n/*\n * Helper functions for managing events -- not part of the public interface.\n * Props to Dean Edwards' addEvent library for many of the ideas.\n */\njQuery.event = {\n\n\tglobal: {},\n\n\tadd: function( elem, types, handler, data, selector ) {\n\n\t\tvar handleObjIn, eventHandle, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.get( elem );\n\n\t\t// Don't attach events to noData or text/comment nodes (but allow plain objects)\n\t\tif ( !elemData ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Caller can pass in an object of custom data in lieu of the handler\n\t\tif ( handler.handler ) {\n\t\t\thandleObjIn = handler;\n\t\t\thandler = handleObjIn.handler;\n\t\t\tselector = handleObjIn.selector;\n\t\t}\n\n\t\t// Make sure that the handler has a unique ID, used to find/remove it later\n\t\tif ( !handler.guid ) {\n\t\t\thandler.guid = jQuery.guid++;\n\t\t}\n\n\t\t// Init the element's event structure and main handler, if this is the first\n\t\tif ( !( events = elemData.events ) ) {\n\t\t\tevents = elemData.events = {};\n\t\t}\n\t\tif ( !( eventHandle = elemData.handle ) ) {\n\t\t\teventHandle = elemData.handle = function( e ) {\n\n\t\t\t\t// Discard the second event of a jQuery.event.trigger() and\n\t\t\t\t// when an event is called after a page has unloaded\n\t\t\t\treturn typeof jQuery !== \"undefined\" && jQuery.event.triggered !== e.type ?\n\t\t\t\t\tjQuery.event.dispatch.apply( elem, arguments ) : undefined;\n\t\t\t};\n\t\t}\n\n\t\t// Handle multiple events separated by a space\n\t\ttypes = ( types || \"\" ).match( rnotwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// There *must* be a type, no attaching namespace-only handlers\n\t\t\tif ( !type ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If event changes its type, use the special event handlers for the changed type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// If selector defined, determine special event api type, otherwise given type\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\n\t\t\t// Update special based on newly reset type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// handleObj is passed to all event handlers\n\t\t\thandleObj = jQuery.extend( {\n\t\t\t\ttype: type,\n\t\t\t\torigType: origType,\n\t\t\t\tdata: data,\n\t\t\t\thandler: handler,\n\t\t\t\tguid: handler.guid,\n\t\t\t\tselector: selector,\n\t\t\t\tneedsContext: selector && jQuery.expr.match.needsContext.test( selector ),\n\t\t\t\tnamespace: namespaces.join( \".\" )\n\t\t\t}, handleObjIn );\n\n\t\t\t// Init the event handler queue if we're the first\n\t\t\tif ( !( handlers = events[ type ] ) ) {\n\t\t\t\thandlers = events[ type ] = [];\n\t\t\t\thandlers.delegateCount = 0;\n\n\t\t\t\t// Only use addEventListener if the special events handler returns false\n\t\t\t\tif ( !special.setup ||\n\t\t\t\t\tspecial.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n\n\t\t\t\t\tif ( elem.addEventListener ) {\n\t\t\t\t\t\telem.addEventListener( type, eventHandle );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( special.add ) {\n\t\t\t\tspecial.add.call( elem, handleObj );\n\n\t\t\t\tif ( !handleObj.handler.guid ) {\n\t\t\t\t\thandleObj.handler.guid = handler.guid;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add to the element's handler list, delegates in front\n\t\t\tif ( selector ) {\n\t\t\t\thandlers.splice( handlers.delegateCount++, 0, handleObj );\n\t\t\t} else {\n\t\t\t\thandlers.push( handleObj );\n\t\t\t}\n\n\t\t\t// Keep track of which events have ever been used, for event optimization\n\t\t\tjQuery.event.global[ type ] = true;\n\t\t}\n\n\t},\n\n\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler, selector, mappedTypes ) {\n\n\t\tvar j, origCount, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.hasData( elem ) && dataPriv.get( elem );\n\n\t\tif ( !elemData || !( events = elemData.events ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Once for each type.namespace in types; type may be omitted\n\t\ttypes = ( types || \"\" ).match( rnotwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// Unbind all events (on this namespace, if provided) for the element\n\t\t\tif ( !type ) {\n\t\t\t\tfor ( type in events ) {\n\t\t\t\t\tjQuery.event.remove( elem, type + types[ t ], handler, selector, true );\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\t\t\thandlers = events[ type ] || [];\n\t\t\ttmp = tmp[ 2 ] &&\n\t\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" );\n\n\t\t\t// Remove matching events\n\t\t\torigCount = j = handlers.length;\n\t\t\twhile ( j-- ) {\n\t\t\t\thandleObj = handlers[ j ];\n\n\t\t\t\tif ( ( mappedTypes || origType === handleObj.origType ) &&\n\t\t\t\t\t( !handler || handler.guid === handleObj.guid ) &&\n\t\t\t\t\t( !tmp || tmp.test( handleObj.namespace ) ) &&\n\t\t\t\t\t( !selector || selector === handleObj.selector ||\n\t\t\t\t\t\tselector === \"**\" && handleObj.selector ) ) {\n\t\t\t\t\thandlers.splice( j, 1 );\n\n\t\t\t\t\tif ( handleObj.selector ) {\n\t\t\t\t\t\thandlers.delegateCount--;\n\t\t\t\t\t}\n\t\t\t\t\tif ( special.remove ) {\n\t\t\t\t\t\tspecial.remove.call( elem, handleObj );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove generic event handler if we removed something and no more handlers exist\n\t\t\t// (avoids potential for endless recursion during removal of special event handlers)\n\t\t\tif ( origCount && !handlers.length ) {\n\t\t\t\tif ( !special.teardown ||\n\t\t\t\t\tspecial.teardown.call( elem, namespaces, elemData.handle ) === false ) {\n\n\t\t\t\t\tjQuery.removeEvent( elem, type, elemData.handle );\n\t\t\t\t}\n\n\t\t\t\tdelete events[ type ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove data and the expando if it's no longer used\n\t\tif ( jQuery.isEmptyObject( events ) ) {\n\t\t\tdataPriv.remove( elem, \"handle events\" );\n\t\t}\n\t},\n\n\tdispatch: function( event ) {\n\n\t\t// Make a writable jQuery.Event from the native event object\n\t\tevent = jQuery.event.fix( event );\n\n\t\tvar i, j, ret, matched, handleObj,\n\t\t\thandlerQueue = [],\n\t\t\targs = slice.call( arguments ),\n\t\t\thandlers = ( dataPriv.get( this, \"events\" ) || {} )[ event.type ] || [],\n\t\t\tspecial = jQuery.event.special[ event.type ] || {};\n\n\t\t// Use the fix-ed jQuery.Event rather than the (read-only) native event\n\t\targs[ 0 ] = event;\n\t\tevent.delegateTarget = this;\n\n\t\t// Call the preDispatch hook for the mapped type, and let it bail if desired\n\t\tif ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine handlers\n\t\thandlerQueue = jQuery.event.handlers.call( this, event, handlers );\n\n\t\t// Run delegates first; they may want to stop propagation beneath us\n\t\ti = 0;\n\t\twhile ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tevent.currentTarget = matched.elem;\n\n\t\t\tj = 0;\n\t\t\twhile ( ( handleObj = matched.handlers[ j++ ] ) &&\n\t\t\t\t!event.isImmediatePropagationStopped() ) {\n\n\t\t\t\t// Triggered event must either 1) have no namespace, or 2) have namespace(s)\n\t\t\t\t// a subset or equal to those in the bound event (both can have no namespace).\n\t\t\t\tif ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) {\n\n\t\t\t\t\tevent.handleObj = handleObj;\n\t\t\t\t\tevent.data = handleObj.data;\n\n\t\t\t\t\tret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||\n\t\t\t\t\t\thandleObj.handler ).apply( matched.elem, args );\n\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\tif ( ( event.result = ret ) === false ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Call the postDispatch hook for the mapped type\n\t\tif ( special.postDispatch ) {\n\t\t\tspecial.postDispatch.call( this, event );\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\thandlers: function( event, handlers ) {\n\t\tvar i, matches, sel, handleObj,\n\t\t\thandlerQueue = [],\n\t\t\tdelegateCount = handlers.delegateCount,\n\t\t\tcur = event.target;\n\n\t\t// Support (at least): Chrome, IE9\n\t\t// Find delegate handlers\n\t\t// Black-hole SVG <use> instance trees (#13180)\n\t\t//\n\t\t// Support: Firefox<=42+\n\t\t// Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343)\n\t\tif ( delegateCount && cur.nodeType &&\n\t\t\t( event.type !== \"click\" || isNaN( event.button ) || event.button < 1 ) ) {\n\n\t\t\tfor ( ; cur !== this; cur = cur.parentNode || this ) {\n\n\t\t\t\t// Don't check non-elements (#13208)\n\t\t\t\t// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)\n\t\t\t\tif ( cur.nodeType === 1 && ( cur.disabled !== true || event.type !== \"click\" ) ) {\n\t\t\t\t\tmatches = [];\n\t\t\t\t\tfor ( i = 0; i < delegateCount; i++ ) {\n\t\t\t\t\t\thandleObj = handlers[ i ];\n\n\t\t\t\t\t\t// Don't conflict with Object.prototype properties (#13203)\n\t\t\t\t\t\tsel = handleObj.selector + \" \";\n\n\t\t\t\t\t\tif ( matches[ sel ] === undefined ) {\n\t\t\t\t\t\t\tmatches[ sel ] = handleObj.needsContext ?\n\t\t\t\t\t\t\t\tjQuery( sel, this ).index( cur ) > -1 :\n\t\t\t\t\t\t\t\tjQuery.find( sel, this, null, [ cur ] ).length;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( matches[ sel ] ) {\n\t\t\t\t\t\t\tmatches.push( handleObj );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( matches.length ) {\n\t\t\t\t\t\thandlerQueue.push( { elem: cur, handlers: matches } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add the remaining (directly-bound) handlers\n\t\tif ( delegateCount < handlers.length ) {\n\t\t\thandlerQueue.push( { elem: this, handlers: handlers.slice( delegateCount ) } );\n\t\t}\n\n\t\treturn handlerQueue;\n\t},\n\n\t// Includes some event props shared by KeyEvent and MouseEvent\n\tprops: ( \"altKey bubbles cancelable ctrlKey currentTarget detail eventPhase \" +\n\t\t\"metaKey relatedTarget shiftKey target timeStamp view which\" ).split( \" \" ),\n\n\tfixHooks: {},\n\n\tkeyHooks: {\n\t\tprops: \"char charCode key keyCode\".split( \" \" ),\n\t\tfilter: function( event, original ) {\n\n\t\t\t// Add which for key events\n\t\t\tif ( event.which == null ) {\n\t\t\t\tevent.which = original.charCode != null ? original.charCode : original.keyCode;\n\t\t\t}\n\n\t\t\treturn event;\n\t\t}\n\t},\n\n\tmouseHooks: {\n\t\tprops: ( \"button buttons clientX clientY offsetX offsetY pageX pageY \" +\n\t\t\t\"screenX screenY toElement\" ).split( \" \" ),\n\t\tfilter: function( event, original ) {\n\t\t\tvar eventDoc, doc, body,\n\t\t\t\tbutton = original.button;\n\n\t\t\t// Calculate pageX/Y if missing and clientX/Y available\n\t\t\tif ( event.pageX == null && original.clientX != null ) {\n\t\t\t\teventDoc = event.target.ownerDocument || document;\n\t\t\t\tdoc = eventDoc.documentElement;\n\t\t\t\tbody = eventDoc.body;\n\n\t\t\t\tevent.pageX = original.clientX +\n\t\t\t\t\t( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) -\n\t\t\t\t\t( doc && doc.clientLeft || body && body.clientLeft || 0 );\n\t\t\t\tevent.pageY = original.clientY +\n\t\t\t\t\t( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) -\n\t\t\t\t\t( doc && doc.clientTop  || body && body.clientTop  || 0 );\n\t\t\t}\n\n\t\t\t// Add which for click: 1 === left; 2 === middle; 3 === right\n\t\t\t// Note: button is not normalized, so don't use it\n\t\t\tif ( !event.which && button !== undefined ) {\n\t\t\t\tevent.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );\n\t\t\t}\n\n\t\t\treturn event;\n\t\t}\n\t},\n\n\tfix: function( event ) {\n\t\tif ( event[ jQuery.expando ] ) {\n\t\t\treturn event;\n\t\t}\n\n\t\t// Create a writable copy of the event object and normalize some properties\n\t\tvar i, prop, copy,\n\t\t\ttype = event.type,\n\t\t\toriginalEvent = event,\n\t\t\tfixHook = this.fixHooks[ type ];\n\n\t\tif ( !fixHook ) {\n\t\t\tthis.fixHooks[ type ] = fixHook =\n\t\t\t\trmouseEvent.test( type ) ? this.mouseHooks :\n\t\t\t\trkeyEvent.test( type ) ? this.keyHooks :\n\t\t\t\t{};\n\t\t}\n\t\tcopy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;\n\n\t\tevent = new jQuery.Event( originalEvent );\n\n\t\ti = copy.length;\n\t\twhile ( i-- ) {\n\t\t\tprop = copy[ i ];\n\t\t\tevent[ prop ] = originalEvent[ prop ];\n\t\t}\n\n\t\t// Support: Cordova 2.5 (WebKit) (#13255)\n\t\t// All events should have a target; Cordova deviceready doesn't\n\t\tif ( !event.target ) {\n\t\t\tevent.target = document;\n\t\t}\n\n\t\t// Support: Safari 6.0+, Chrome<28\n\t\t// Target should not be a text node (#504, #13143)\n\t\tif ( event.target.nodeType === 3 ) {\n\t\t\tevent.target = event.target.parentNode;\n\t\t}\n\n\t\treturn fixHook.filter ? fixHook.filter( event, originalEvent ) : event;\n\t},\n\n\tspecial: {\n\t\tload: {\n\n\t\t\t// Prevent triggered image.load events from bubbling to window.load\n\t\t\tnoBubble: true\n\t\t},\n\t\tfocus: {\n\n\t\t\t// Fire native event if possible so blur/focus sequence is correct\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this !== safeActiveElement() && this.focus ) {\n\t\t\t\t\tthis.focus();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdelegateType: \"focusin\"\n\t\t},\n\t\tblur: {\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this === safeActiveElement() && this.blur ) {\n\t\t\t\t\tthis.blur();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdelegateType: \"focusout\"\n\t\t},\n\t\tclick: {\n\n\t\t\t// For checkbox, fire native event so checked state will be right\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this.type === \"checkbox\" && this.click && jQuery.nodeName( this, \"input\" ) ) {\n\t\t\t\t\tthis.click();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// For cross-browser consistency, don't fire native .click() on links\n\t\t\t_default: function( event ) {\n\t\t\t\treturn jQuery.nodeName( event.target, \"a\" );\n\t\t\t}\n\t\t},\n\n\t\tbeforeunload: {\n\t\t\tpostDispatch: function( event ) {\n\n\t\t\t\t// Support: Firefox 20+\n\t\t\t\t// Firefox doesn't alert if the returnValue field is not set.\n\t\t\t\tif ( event.result !== undefined && event.originalEvent ) {\n\t\t\t\t\tevent.originalEvent.returnValue = event.result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n};\n\njQuery.removeEvent = function( elem, type, handle ) {\n\n\t// This \"if\" is needed for plain objects\n\tif ( elem.removeEventListener ) {\n\t\telem.removeEventListener( type, handle );\n\t}\n};\n\njQuery.Event = function( src, props ) {\n\n\t// Allow instantiation without the 'new' keyword\n\tif ( !( this instanceof jQuery.Event ) ) {\n\t\treturn new jQuery.Event( src, props );\n\t}\n\n\t// Event object\n\tif ( src && src.type ) {\n\t\tthis.originalEvent = src;\n\t\tthis.type = src.type;\n\n\t\t// Events bubbling up the document may have been marked as prevented\n\t\t// by a handler lower down the tree; reflect the correct value.\n\t\tthis.isDefaultPrevented = src.defaultPrevented ||\n\t\t\t\tsrc.defaultPrevented === undefined &&\n\n\t\t\t\t// Support: Android<4.0\n\t\t\t\tsrc.returnValue === false ?\n\t\t\treturnTrue :\n\t\t\treturnFalse;\n\n\t// Event type\n\t} else {\n\t\tthis.type = src;\n\t}\n\n\t// Put explicitly provided properties onto the event object\n\tif ( props ) {\n\t\tjQuery.extend( this, props );\n\t}\n\n\t// Create a timestamp if incoming event doesn't have one\n\tthis.timeStamp = src && src.timeStamp || jQuery.now();\n\n\t// Mark it as fixed\n\tthis[ jQuery.expando ] = true;\n};\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\njQuery.Event.prototype = {\n\tconstructor: jQuery.Event,\n\tisDefaultPrevented: returnFalse,\n\tisPropagationStopped: returnFalse,\n\tisImmediatePropagationStopped: returnFalse,\n\n\tpreventDefault: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isDefaultPrevented = returnTrue;\n\n\t\tif ( e ) {\n\t\t\te.preventDefault();\n\t\t}\n\t},\n\tstopPropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isPropagationStopped = returnTrue;\n\n\t\tif ( e ) {\n\t\t\te.stopPropagation();\n\t\t}\n\t},\n\tstopImmediatePropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\n\t\tif ( e ) {\n\t\t\te.stopImmediatePropagation();\n\t\t}\n\n\t\tthis.stopPropagation();\n\t}\n};\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\n// so that event delegation works in jQuery.\n// Do the same for pointerenter/pointerleave and pointerover/pointerout\n//\n// Support: Safari 7 only\n// Safari sends mouseenter too often; see:\n// https://code.google.com/p/chromium/issues/detail?id=470258\n// for the description of the bug (it existed in older Chrome versions as well).\njQuery.each( {\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\",\n\tpointerenter: \"pointerover\",\n\tpointerleave: \"pointerout\"\n}, function( orig, fix ) {\n\tjQuery.event.special[ orig ] = {\n\t\tdelegateType: fix,\n\t\tbindType: fix,\n\n\t\thandle: function( event ) {\n\t\t\tvar ret,\n\t\t\t\ttarget = this,\n\t\t\t\trelated = event.relatedTarget,\n\t\t\t\thandleObj = event.handleObj;\n\n\t\t\t// For mouseenter/leave call the handler if related is outside the target.\n\t\t\t// NB: No relatedTarget if the mouse left/entered the browser window\n\t\t\tif ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {\n\t\t\t\tevent.type = handleObj.origType;\n\t\t\t\tret = handleObj.handler.apply( this, arguments );\n\t\t\t\tevent.type = fix;\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t};\n} );\n\njQuery.fn.extend( {\n\ton: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn );\n\t},\n\tone: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn, 1 );\n\t},\n\toff: function( types, selector, fn ) {\n\t\tvar handleObj, type;\n\t\tif ( types && types.preventDefault && types.handleObj ) {\n\n\t\t\t// ( event )  dispatched jQuery.Event\n\t\t\thandleObj = types.handleObj;\n\t\t\tjQuery( types.delegateTarget ).off(\n\t\t\t\thandleObj.namespace ?\n\t\t\t\t\thandleObj.origType + \".\" + handleObj.namespace :\n\t\t\t\t\thandleObj.origType,\n\t\t\t\thandleObj.selector,\n\t\t\t\thandleObj.handler\n\t\t\t);\n\t\t\treturn this;\n\t\t}\n\t\tif ( typeof types === \"object\" ) {\n\n\t\t\t// ( types-object [, selector] )\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.off( type, selector, types[ type ] );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif ( selector === false || typeof selector === \"function\" ) {\n\n\t\t\t// ( types [, fn] )\n\t\t\tfn = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.remove( this, types, fn, selector );\n\t\t} );\n\t}\n} );\n\n\nvar\n\trxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:-]+)[^>]*)\\/>/gi,\n\n\t// Support: IE 10-11, Edge 10240+\n\t// In IE/Edge using regex groups here causes severe slowdowns.\n\t// See https://connect.microsoft.com/IE/feedback/details/1736512/\n\trnoInnerhtml = /<script|<style|<link/i,\n\n\t// checked=\"checked\" or checked\n\trchecked = /checked\\s*(?:[^=]|=\\s*.checked.)/i,\n\trscriptTypeMasked = /^true\\/(.*)/,\n\trcleanScript = /^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g;\n\n// Manipulating tables requires a tbody\nfunction manipulationTarget( elem, content ) {\n\treturn jQuery.nodeName( elem, \"table\" ) &&\n\t\tjQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, \"tr\" ) ?\n\n\t\telem.getElementsByTagName( \"tbody\" )[ 0 ] ||\n\t\t\telem.appendChild( elem.ownerDocument.createElement( \"tbody\" ) ) :\n\t\telem;\n}\n\n// Replace/restore the type attribute of script elements for safe DOM manipulation\nfunction disableScript( elem ) {\n\telem.type = ( elem.getAttribute( \"type\" ) !== null ) + \"/\" + elem.type;\n\treturn elem;\n}\nfunction restoreScript( elem ) {\n\tvar match = rscriptTypeMasked.exec( elem.type );\n\n\tif ( match ) {\n\t\telem.type = match[ 1 ];\n\t} else {\n\t\telem.removeAttribute( \"type\" );\n\t}\n\n\treturn elem;\n}\n\nfunction cloneCopyEvent( src, dest ) {\n\tvar i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;\n\n\tif ( dest.nodeType !== 1 ) {\n\t\treturn;\n\t}\n\n\t// 1. Copy private data: events, handlers, etc.\n\tif ( dataPriv.hasData( src ) ) {\n\t\tpdataOld = dataPriv.access( src );\n\t\tpdataCur = dataPriv.set( dest, pdataOld );\n\t\tevents = pdataOld.events;\n\n\t\tif ( events ) {\n\t\t\tdelete pdataCur.handle;\n\t\t\tpdataCur.events = {};\n\n\t\t\tfor ( type in events ) {\n\t\t\t\tfor ( i = 0, l = events[ type ].length; i < l; i++ ) {\n\t\t\t\t\tjQuery.event.add( dest, type, events[ type ][ i ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// 2. Copy user data\n\tif ( dataUser.hasData( src ) ) {\n\t\tudataOld = dataUser.access( src );\n\t\tudataCur = jQuery.extend( {}, udataOld );\n\n\t\tdataUser.set( dest, udataCur );\n\t}\n}\n\n// Fix IE bugs, see support tests\nfunction fixInput( src, dest ) {\n\tvar nodeName = dest.nodeName.toLowerCase();\n\n\t// Fails to persist the checked state of a cloned checkbox or radio button.\n\tif ( nodeName === \"input\" && rcheckableType.test( src.type ) ) {\n\t\tdest.checked = src.checked;\n\n\t// Fails to return the selected option to the default selected state when cloning options\n\t} else if ( nodeName === \"input\" || nodeName === \"textarea\" ) {\n\t\tdest.defaultValue = src.defaultValue;\n\t}\n}\n\nfunction domManip( collection, args, callback, ignored ) {\n\n\t// Flatten any nested arrays\n\targs = concat.apply( [], args );\n\n\tvar fragment, first, scripts, hasScripts, node, doc,\n\t\ti = 0,\n\t\tl = collection.length,\n\t\tiNoClone = l - 1,\n\t\tvalue = args[ 0 ],\n\t\tisFunction = jQuery.isFunction( value );\n\n\t// We can't cloneNode fragments that contain checked, in WebKit\n\tif ( isFunction ||\n\t\t\t( l > 1 && typeof value === \"string\" &&\n\t\t\t\t!support.checkClone && rchecked.test( value ) ) ) {\n\t\treturn collection.each( function( index ) {\n\t\t\tvar self = collection.eq( index );\n\t\t\tif ( isFunction ) {\n\t\t\t\targs[ 0 ] = value.call( this, index, self.html() );\n\t\t\t}\n\t\t\tdomManip( self, args, callback, ignored );\n\t\t} );\n\t}\n\n\tif ( l ) {\n\t\tfragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );\n\t\tfirst = fragment.firstChild;\n\n\t\tif ( fragment.childNodes.length === 1 ) {\n\t\t\tfragment = first;\n\t\t}\n\n\t\t// Require either new content or an interest in ignored elements to invoke the callback\n\t\tif ( first || ignored ) {\n\t\t\tscripts = jQuery.map( getAll( fragment, \"script\" ), disableScript );\n\t\t\thasScripts = scripts.length;\n\n\t\t\t// Use the original fragment for the last item\n\t\t\t// instead of the first because it can end up\n\t\t\t// being emptied incorrectly in certain situations (#8070).\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tnode = fragment;\n\n\t\t\t\tif ( i !== iNoClone ) {\n\t\t\t\t\tnode = jQuery.clone( node, true, true );\n\n\t\t\t\t\t// Keep references to cloned scripts for later restoration\n\t\t\t\t\tif ( hasScripts ) {\n\n\t\t\t\t\t\t// Support: Android<4.1, PhantomJS<2\n\t\t\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\t\t\tjQuery.merge( scripts, getAll( node, \"script\" ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcallback.call( collection[ i ], node, i );\n\t\t\t}\n\n\t\t\tif ( hasScripts ) {\n\t\t\t\tdoc = scripts[ scripts.length - 1 ].ownerDocument;\n\n\t\t\t\t// Reenable scripts\n\t\t\t\tjQuery.map( scripts, restoreScript );\n\n\t\t\t\t// Evaluate executable scripts on first document insertion\n\t\t\t\tfor ( i = 0; i < hasScripts; i++ ) {\n\t\t\t\t\tnode = scripts[ i ];\n\t\t\t\t\tif ( rscriptType.test( node.type || \"\" ) &&\n\t\t\t\t\t\t!dataPriv.access( node, \"globalEval\" ) &&\n\t\t\t\t\t\tjQuery.contains( doc, node ) ) {\n\n\t\t\t\t\t\tif ( node.src ) {\n\n\t\t\t\t\t\t\t// Optional AJAX dependency, but won't run scripts if not present\n\t\t\t\t\t\t\tif ( jQuery._evalUrl ) {\n\t\t\t\t\t\t\t\tjQuery._evalUrl( node.src );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tjQuery.globalEval( node.textContent.replace( rcleanScript, \"\" ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn collection;\n}\n\nfunction remove( elem, selector, keepData ) {\n\tvar node,\n\t\tnodes = selector ? jQuery.filter( selector, elem ) : elem,\n\t\ti = 0;\n\n\tfor ( ; ( node = nodes[ i ] ) != null; i++ ) {\n\t\tif ( !keepData && node.nodeType === 1 ) {\n\t\t\tjQuery.cleanData( getAll( node ) );\n\t\t}\n\n\t\tif ( node.parentNode ) {\n\t\t\tif ( keepData && jQuery.contains( node.ownerDocument, node ) ) {\n\t\t\t\tsetGlobalEval( getAll( node, \"script\" ) );\n\t\t\t}\n\t\t\tnode.parentNode.removeChild( node );\n\t\t}\n\t}\n\n\treturn elem;\n}\n\njQuery.extend( {\n\thtmlPrefilter: function( html ) {\n\t\treturn html.replace( rxhtmlTag, \"<$1></$2>\" );\n\t},\n\n\tclone: function( elem, dataAndEvents, deepDataAndEvents ) {\n\t\tvar i, l, srcElements, destElements,\n\t\t\tclone = elem.cloneNode( true ),\n\t\t\tinPage = jQuery.contains( elem.ownerDocument, elem );\n\n\t\t// Fix IE cloning issues\n\t\tif ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&\n\t\t\t\t!jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2\n\t\t\tdestElements = getAll( clone );\n\t\t\tsrcElements = getAll( elem );\n\n\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\tfixInput( srcElements[ i ], destElements[ i ] );\n\t\t\t}\n\t\t}\n\n\t\t// Copy the events from the original to the clone\n\t\tif ( dataAndEvents ) {\n\t\t\tif ( deepDataAndEvents ) {\n\t\t\t\tsrcElements = srcElements || getAll( elem );\n\t\t\t\tdestElements = destElements || getAll( clone );\n\n\t\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\t\tcloneCopyEvent( srcElements[ i ], destElements[ i ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcloneCopyEvent( elem, clone );\n\t\t\t}\n\t\t}\n\n\t\t// Preserve script evaluation history\n\t\tdestElements = getAll( clone, \"script\" );\n\t\tif ( destElements.length > 0 ) {\n\t\t\tsetGlobalEval( destElements, !inPage && getAll( elem, \"script\" ) );\n\t\t}\n\n\t\t// Return the cloned set\n\t\treturn clone;\n\t},\n\n\tcleanData: function( elems ) {\n\t\tvar data, elem, type,\n\t\t\tspecial = jQuery.event.special,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {\n\t\t\tif ( acceptData( elem ) ) {\n\t\t\t\tif ( ( data = elem[ dataPriv.expando ] ) ) {\n\t\t\t\t\tif ( data.events ) {\n\t\t\t\t\t\tfor ( type in data.events ) {\n\t\t\t\t\t\t\tif ( special[ type ] ) {\n\t\t\t\t\t\t\t\tjQuery.event.remove( elem, type );\n\n\t\t\t\t\t\t\t// This is a shortcut to avoid jQuery.event.remove's overhead\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.removeEvent( elem, type, data.handle );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Support: Chrome <= 35-45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataPriv.expando ] = undefined;\n\t\t\t\t}\n\t\t\t\tif ( elem[ dataUser.expando ] ) {\n\n\t\t\t\t\t// Support: Chrome <= 35-45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataUser.expando ] = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n} );\n\njQuery.fn.extend( {\n\n\t// Keep domManip exposed until 3.0 (gh-2225)\n\tdomManip: domManip,\n\n\tdetach: function( selector ) {\n\t\treturn remove( this, selector, true );\n\t},\n\n\tremove: function( selector ) {\n\t\treturn remove( this, selector );\n\t},\n\n\ttext: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\treturn value === undefined ?\n\t\t\t\tjQuery.text( this ) :\n\t\t\t\tthis.empty().each( function() {\n\t\t\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\t\t\tthis.textContent = value;\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t}, null, value, arguments.length );\n\t},\n\n\tappend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.appendChild( elem );\n\t\t\t}\n\t\t} );\n\t},\n\n\tprepend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.insertBefore( elem, target.firstChild );\n\t\t\t}\n\t\t} );\n\t},\n\n\tbefore: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this );\n\t\t\t}\n\t\t} );\n\t},\n\n\tafter: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n\t\t\t}\n\t\t} );\n\t},\n\n\tempty: function() {\n\t\tvar elem,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = this[ i ] ) != null; i++ ) {\n\t\t\tif ( elem.nodeType === 1 ) {\n\n\t\t\t\t// Prevent memory leaks\n\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\n\t\t\t\t// Remove any remaining nodes\n\t\t\t\telem.textContent = \"\";\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tclone: function( dataAndEvents, deepDataAndEvents ) {\n\t\tdataAndEvents = dataAndEvents == null ? false : dataAndEvents;\n\t\tdeepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;\n\n\t\treturn this.map( function() {\n\t\t\treturn jQuery.clone( this, dataAndEvents, deepDataAndEvents );\n\t\t} );\n\t},\n\n\thtml: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\tvar elem = this[ 0 ] || {},\n\t\t\t\ti = 0,\n\t\t\t\tl = this.length;\n\n\t\t\tif ( value === undefined && elem.nodeType === 1 ) {\n\t\t\t\treturn elem.innerHTML;\n\t\t\t}\n\n\t\t\t// See if we can take a shortcut and just use innerHTML\n\t\t\tif ( typeof value === \"string\" && !rnoInnerhtml.test( value ) &&\n\t\t\t\t!wrapMap[ ( rtagName.exec( value ) || [ \"\", \"\" ] )[ 1 ].toLowerCase() ] ) {\n\n\t\t\t\tvalue = jQuery.htmlPrefilter( value );\n\n\t\t\t\ttry {\n\t\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\t\telem = this[ i ] || {};\n\n\t\t\t\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\t\t\t\t\t\t\telem.innerHTML = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telem = 0;\n\n\t\t\t\t// If using innerHTML throws an exception, use the fallback method\n\t\t\t\t} catch ( e ) {}\n\t\t\t}\n\n\t\t\tif ( elem ) {\n\t\t\t\tthis.empty().append( value );\n\t\t\t}\n\t\t}, null, value, arguments.length );\n\t},\n\n\treplaceWith: function() {\n\t\tvar ignored = [];\n\n\t\t// Make the changes, replacing each non-ignored context element with the new content\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tvar parent = this.parentNode;\n\n\t\t\tif ( jQuery.inArray( this, ignored ) < 0 ) {\n\t\t\t\tjQuery.cleanData( getAll( this ) );\n\t\t\t\tif ( parent ) {\n\t\t\t\t\tparent.replaceChild( elem, this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Force callback invocation\n\t\t}, ignored );\n\t}\n} );\n\njQuery.each( {\n\tappendTo: \"append\",\n\tprependTo: \"prepend\",\n\tinsertBefore: \"before\",\n\tinsertAfter: \"after\",\n\treplaceAll: \"replaceWith\"\n}, function( name, original ) {\n\tjQuery.fn[ name ] = function( selector ) {\n\t\tvar elems,\n\t\t\tret = [],\n\t\t\tinsert = jQuery( selector ),\n\t\t\tlast = insert.length - 1,\n\t\t\ti = 0;\n\n\t\tfor ( ; i <= last; i++ ) {\n\t\t\telems = i === last ? this : this.clone( true );\n\t\t\tjQuery( insert[ i ] )[ original ]( elems );\n\n\t\t\t// Support: QtWebKit\n\t\t\t// .get() because push.apply(_, arraylike) throws\n\t\t\tpush.apply( ret, elems.get() );\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n} );\n\n\nvar iframe,\n\telemdisplay = {\n\n\t\t// Support: Firefox\n\t\t// We have to pre-define these values for FF (#10227)\n\t\tHTML: \"block\",\n\t\tBODY: \"block\"\n\t};\n\n/**\n * Retrieve the actual display of a element\n * @param {String} name nodeName of the element\n * @param {Object} doc Document object\n */\n\n// Called only from within defaultDisplay\nfunction actualDisplay( name, doc ) {\n\tvar elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),\n\n\t\tdisplay = jQuery.css( elem[ 0 ], \"display\" );\n\n\t// We don't have any data stored on the element,\n\t// so use \"detach\" method as fast way to get rid of the element\n\telem.detach();\n\n\treturn display;\n}\n\n/**\n * Try to determine the default display value of an element\n * @param {String} nodeName\n */\nfunction defaultDisplay( nodeName ) {\n\tvar doc = document,\n\t\tdisplay = elemdisplay[ nodeName ];\n\n\tif ( !display ) {\n\t\tdisplay = actualDisplay( nodeName, doc );\n\n\t\t// If the simple way fails, read from inside an iframe\n\t\tif ( display === \"none\" || !display ) {\n\n\t\t\t// Use the already-created iframe if possible\n\t\t\tiframe = ( iframe || jQuery( \"<iframe frameborder='0' width='0' height='0'/>\" ) )\n\t\t\t\t.appendTo( doc.documentElement );\n\n\t\t\t// Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse\n\t\t\tdoc = iframe[ 0 ].contentDocument;\n\n\t\t\t// Support: IE\n\t\t\tdoc.write();\n\t\t\tdoc.close();\n\n\t\t\tdisplay = actualDisplay( nodeName, doc );\n\t\t\tiframe.detach();\n\t\t}\n\n\t\t// Store the correct default display\n\t\telemdisplay[ nodeName ] = display;\n\t}\n\n\treturn display;\n}\nvar rmargin = ( /^margin/ );\n\nvar rnumnonpx = new RegExp( \"^(\" + pnum + \")(?!px)[a-z%]+$\", \"i\" );\n\nvar getStyles = function( elem ) {\n\n\t\t// Support: IE<=11+, Firefox<=30+ (#15098, #14150)\n\t\t// IE throws on elements created in popups\n\t\t// FF meanwhile throws on frame elements through \"defaultView.getComputedStyle\"\n\t\tvar view = elem.ownerDocument.defaultView;\n\n\t\tif ( !view || !view.opener ) {\n\t\t\tview = window;\n\t\t}\n\n\t\treturn view.getComputedStyle( elem );\n\t};\n\nvar swap = function( elem, options, callback, args ) {\n\tvar ret, name,\n\t\told = {};\n\n\t// Remember the old values, and insert the new ones\n\tfor ( name in options ) {\n\t\told[ name ] = elem.style[ name ];\n\t\telem.style[ name ] = options[ name ];\n\t}\n\n\tret = callback.apply( elem, args || [] );\n\n\t// Revert the old values\n\tfor ( name in options ) {\n\t\telem.style[ name ] = old[ name ];\n\t}\n\n\treturn ret;\n};\n\n\nvar documentElement = document.documentElement;\n\n\n\n( function() {\n\tvar pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal,\n\t\tcontainer = document.createElement( \"div\" ),\n\t\tdiv = document.createElement( \"div\" );\n\n\t// Finish early in limited (non-browser) environments\n\tif ( !div.style ) {\n\t\treturn;\n\t}\n\n\t// Support: IE9-11+\n\t// Style of cloned element affects source element cloned (#8908)\n\tdiv.style.backgroundClip = \"content-box\";\n\tdiv.cloneNode( true ).style.backgroundClip = \"\";\n\tsupport.clearCloneStyle = div.style.backgroundClip === \"content-box\";\n\n\tcontainer.style.cssText = \"border:0;width:8px;height:0;top:0;left:-9999px;\" +\n\t\t\"padding:0;margin-top:1px;position:absolute\";\n\tcontainer.appendChild( div );\n\n\t// Executing both pixelPosition & boxSizingReliable tests require only one layout\n\t// so they're executed at the same time to save the second computation.\n\tfunction computeStyleTests() {\n\t\tdiv.style.cssText =\n\n\t\t\t// Support: Firefox<29, Android 2.3\n\t\t\t// Vendor-prefix box-sizing\n\t\t\t\"-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;\" +\n\t\t\t\"position:relative;display:block;\" +\n\t\t\t\"margin:auto;border:1px;padding:1px;\" +\n\t\t\t\"top:1%;width:50%\";\n\t\tdiv.innerHTML = \"\";\n\t\tdocumentElement.appendChild( container );\n\n\t\tvar divStyle = window.getComputedStyle( div );\n\t\tpixelPositionVal = divStyle.top !== \"1%\";\n\t\treliableMarginLeftVal = divStyle.marginLeft === \"2px\";\n\t\tboxSizingReliableVal = divStyle.width === \"4px\";\n\n\t\t// Support: Android 4.0 - 4.3 only\n\t\t// Some styles come back with percentage values, even though they shouldn't\n\t\tdiv.style.marginRight = \"50%\";\n\t\tpixelMarginRightVal = divStyle.marginRight === \"4px\";\n\n\t\tdocumentElement.removeChild( container );\n\t}\n\n\tjQuery.extend( support, {\n\t\tpixelPosition: function() {\n\n\t\t\t// This test is executed only once but we still do memoizing\n\t\t\t// since we can use the boxSizingReliable pre-computing.\n\t\t\t// No need to check if the test was already performed, though.\n\t\t\tcomputeStyleTests();\n\t\t\treturn pixelPositionVal;\n\t\t},\n\t\tboxSizingReliable: function() {\n\t\t\tif ( boxSizingReliableVal == null ) {\n\t\t\t\tcomputeStyleTests();\n\t\t\t}\n\t\t\treturn boxSizingReliableVal;\n\t\t},\n\t\tpixelMarginRight: function() {\n\n\t\t\t// Support: Android 4.0-4.3\n\t\t\t// We're checking for boxSizingReliableVal here instead of pixelMarginRightVal\n\t\t\t// since that compresses better and they're computed together anyway.\n\t\t\tif ( boxSizingReliableVal == null ) {\n\t\t\t\tcomputeStyleTests();\n\t\t\t}\n\t\t\treturn pixelMarginRightVal;\n\t\t},\n\t\treliableMarginLeft: function() {\n\n\t\t\t// Support: IE <=8 only, Android 4.0 - 4.3 only, Firefox <=3 - 37\n\t\t\tif ( boxSizingReliableVal == null ) {\n\t\t\t\tcomputeStyleTests();\n\t\t\t}\n\t\t\treturn reliableMarginLeftVal;\n\t\t},\n\t\treliableMarginRight: function() {\n\n\t\t\t// Support: Android 2.3\n\t\t\t// Check if div with explicit width and no margin-right incorrectly\n\t\t\t// gets computed margin-right based on width of container. (#3333)\n\t\t\t// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right\n\t\t\t// This support function is only executed once so no memoizing is needed.\n\t\t\tvar ret,\n\t\t\t\tmarginDiv = div.appendChild( document.createElement( \"div\" ) );\n\n\t\t\t// Reset CSS: box-sizing; display; margin; border; padding\n\t\t\tmarginDiv.style.cssText = div.style.cssText =\n\n\t\t\t\t// Support: Android 2.3\n\t\t\t\t// Vendor-prefix box-sizing\n\t\t\t\t\"-webkit-box-sizing:content-box;box-sizing:content-box;\" +\n\t\t\t\t\"display:block;margin:0;border:0;padding:0\";\n\t\t\tmarginDiv.style.marginRight = marginDiv.style.width = \"0\";\n\t\t\tdiv.style.width = \"1px\";\n\t\t\tdocumentElement.appendChild( container );\n\n\t\t\tret = !parseFloat( window.getComputedStyle( marginDiv ).marginRight );\n\n\t\t\tdocumentElement.removeChild( container );\n\t\t\tdiv.removeChild( marginDiv );\n\n\t\t\treturn ret;\n\t\t}\n\t} );\n} )();\n\n\nfunction curCSS( elem, name, computed ) {\n\tvar width, minWidth, maxWidth, ret,\n\t\tstyle = elem.style;\n\n\tcomputed = computed || getStyles( elem );\n\tret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined;\n\n\t// Support: Opera 12.1x only\n\t// Fall back to style even without computed\n\t// computed is undefined for elems on document fragments\n\tif ( ( ret === \"\" || ret === undefined ) && !jQuery.contains( elem.ownerDocument, elem ) ) {\n\t\tret = jQuery.style( elem, name );\n\t}\n\n\t// Support: IE9\n\t// getPropertyValue is only needed for .css('filter') (#12537)\n\tif ( computed ) {\n\n\t\t// A tribute to the \"awesome hack by Dean Edwards\"\n\t\t// Android Browser returns percentage for some values,\n\t\t// but width seems to be reliably pixels.\n\t\t// This is against the CSSOM draft spec:\n\t\t// http://dev.w3.org/csswg/cssom/#resolved-values\n\t\tif ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) {\n\n\t\t\t// Remember the original values\n\t\t\twidth = style.width;\n\t\t\tminWidth = style.minWidth;\n\t\t\tmaxWidth = style.maxWidth;\n\n\t\t\t// Put in the new values to get a computed value out\n\t\t\tstyle.minWidth = style.maxWidth = style.width = ret;\n\t\t\tret = computed.width;\n\n\t\t\t// Revert the changed values\n\t\t\tstyle.width = width;\n\t\t\tstyle.minWidth = minWidth;\n\t\t\tstyle.maxWidth = maxWidth;\n\t\t}\n\t}\n\n\treturn ret !== undefined ?\n\n\t\t// Support: IE9-11+\n\t\t// IE returns zIndex value as an integer.\n\t\tret + \"\" :\n\t\tret;\n}\n\n\nfunction addGetHookIf( conditionFn, hookFn ) {\n\n\t// Define the hook, we'll check on the first run if it's really needed.\n\treturn {\n\t\tget: function() {\n\t\t\tif ( conditionFn() ) {\n\n\t\t\t\t// Hook not needed (or it's not possible to use it due\n\t\t\t\t// to missing dependency), remove it.\n\t\t\t\tdelete this.get;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Hook needed; redefine it so that the support test is not executed again.\n\t\t\treturn ( this.get = hookFn ).apply( this, arguments );\n\t\t}\n\t};\n}\n\n\nvar\n\n\t// Swappable if display is none or starts with table\n\t// except \"table\", \"table-cell\", or \"table-caption\"\n\t// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display\n\trdisplayswap = /^(none|table(?!-c[ea]).+)/,\n\n\tcssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\tcssNormalTransform = {\n\t\tletterSpacing: \"0\",\n\t\tfontWeight: \"400\"\n\t},\n\n\tcssPrefixes = [ \"Webkit\", \"O\", \"Moz\", \"ms\" ],\n\temptyStyle = document.createElement( \"div\" ).style;\n\n// Return a css property mapped to a potentially vendor prefixed property\nfunction vendorPropName( name ) {\n\n\t// Shortcut for names that are not vendor prefixed\n\tif ( name in emptyStyle ) {\n\t\treturn name;\n\t}\n\n\t// Check for vendor prefixed names\n\tvar capName = name[ 0 ].toUpperCase() + name.slice( 1 ),\n\t\ti = cssPrefixes.length;\n\n\twhile ( i-- ) {\n\t\tname = cssPrefixes[ i ] + capName;\n\t\tif ( name in emptyStyle ) {\n\t\t\treturn name;\n\t\t}\n\t}\n}\n\nfunction setPositiveNumber( elem, value, subtract ) {\n\n\t// Any relative (+/-) values have already been\n\t// normalized at this point\n\tvar matches = rcssNum.exec( value );\n\treturn matches ?\n\n\t\t// Guard against undefined \"subtract\", e.g., when used as in cssHooks\n\t\tMath.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || \"px\" ) :\n\t\tvalue;\n}\n\nfunction augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {\n\tvar i = extra === ( isBorderBox ? \"border\" : \"content\" ) ?\n\n\t\t// If we already have the right measurement, avoid augmentation\n\t\t4 :\n\n\t\t// Otherwise initialize for horizontal or vertical properties\n\t\tname === \"width\" ? 1 : 0,\n\n\t\tval = 0;\n\n\tfor ( ; i < 4; i += 2 ) {\n\n\t\t// Both box models exclude margin, so add it if we want it\n\t\tif ( extra === \"margin\" ) {\n\t\t\tval += jQuery.css( elem, extra + cssExpand[ i ], true, styles );\n\t\t}\n\n\t\tif ( isBorderBox ) {\n\n\t\t\t// border-box includes padding, so remove it if we want content\n\t\t\tif ( extra === \"content\" ) {\n\t\t\t\tval -= jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\t\t\t}\n\n\t\t\t// At this point, extra isn't border nor margin, so remove border\n\t\t\tif ( extra !== \"margin\" ) {\n\t\t\t\tval -= jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t} else {\n\n\t\t\t// At this point, extra isn't content, so add padding\n\t\t\tval += jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\n\t\t\t// At this point, extra isn't content nor padding, so add border\n\t\t\tif ( extra !== \"padding\" ) {\n\t\t\t\tval += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn val;\n}\n\nfunction getWidthOrHeight( elem, name, extra ) {\n\n\t// Start with offset property, which is equivalent to the border-box value\n\tvar valueIsBorderBox = true,\n\t\tval = name === \"width\" ? elem.offsetWidth : elem.offsetHeight,\n\t\tstyles = getStyles( elem ),\n\t\tisBorderBox = jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\";\n\n\t// Support: IE11 only\n\t// In IE 11 fullscreen elements inside of an iframe have\n\t// 100x too small dimensions (gh-1764).\n\tif ( document.msFullscreenElement && window.top !== window ) {\n\n\t\t// Support: IE11 only\n\t\t// Running getBoundingClientRect on a disconnected node\n\t\t// in IE throws an error.\n\t\tif ( elem.getClientRects().length ) {\n\t\t\tval = Math.round( elem.getBoundingClientRect()[ name ] * 100 );\n\t\t}\n\t}\n\n\t// Some non-html elements return undefined for offsetWidth, so check for null/undefined\n\t// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285\n\t// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668\n\tif ( val <= 0 || val == null ) {\n\n\t\t// Fall back to computed then uncomputed css if necessary\n\t\tval = curCSS( elem, name, styles );\n\t\tif ( val < 0 || val == null ) {\n\t\t\tval = elem.style[ name ];\n\t\t}\n\n\t\t// Computed unit is not pixels. Stop here and return.\n\t\tif ( rnumnonpx.test( val ) ) {\n\t\t\treturn val;\n\t\t}\n\n\t\t// Check for style in case a browser which returns unreliable values\n\t\t// for getComputedStyle silently falls back to the reliable elem.style\n\t\tvalueIsBorderBox = isBorderBox &&\n\t\t\t( support.boxSizingReliable() || val === elem.style[ name ] );\n\n\t\t// Normalize \"\", auto, and prepare for extra\n\t\tval = parseFloat( val ) || 0;\n\t}\n\n\t// Use the active box-sizing model to add/subtract irrelevant styles\n\treturn ( val +\n\t\taugmentWidthOrHeight(\n\t\t\telem,\n\t\t\tname,\n\t\t\textra || ( isBorderBox ? \"border\" : \"content\" ),\n\t\t\tvalueIsBorderBox,\n\t\t\tstyles\n\t\t)\n\t) + \"px\";\n}\n\nfunction showHide( elements, show ) {\n\tvar display, elem, hidden,\n\t\tvalues = [],\n\t\tindex = 0,\n\t\tlength = elements.length;\n\n\tfor ( ; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tvalues[ index ] = dataPriv.get( elem, \"olddisplay\" );\n\t\tdisplay = elem.style.display;\n\t\tif ( show ) {\n\n\t\t\t// Reset the inline display of this element to learn if it is\n\t\t\t// being hidden by cascaded rules or not\n\t\t\tif ( !values[ index ] && display === \"none\" ) {\n\t\t\t\telem.style.display = \"\";\n\t\t\t}\n\n\t\t\t// Set elements which have been overridden with display: none\n\t\t\t// in a stylesheet to whatever the default browser style is\n\t\t\t// for such an element\n\t\t\tif ( elem.style.display === \"\" && isHidden( elem ) ) {\n\t\t\t\tvalues[ index ] = dataPriv.access(\n\t\t\t\t\telem,\n\t\t\t\t\t\"olddisplay\",\n\t\t\t\t\tdefaultDisplay( elem.nodeName )\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\thidden = isHidden( elem );\n\n\t\t\tif ( display !== \"none\" || !hidden ) {\n\t\t\t\tdataPriv.set(\n\t\t\t\t\telem,\n\t\t\t\t\t\"olddisplay\",\n\t\t\t\t\thidden ? display : jQuery.css( elem, \"display\" )\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set the display of most of the elements in a second loop\n\t// to avoid the constant reflow\n\tfor ( index = 0; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( !show || elem.style.display === \"none\" || elem.style.display === \"\" ) {\n\t\t\telem.style.display = show ? values[ index ] || \"\" : \"none\";\n\t\t}\n\t}\n\n\treturn elements;\n}\n\njQuery.extend( {\n\n\t// Add in style property hooks for overriding the default\n\t// behavior of getting and setting a style property\n\tcssHooks: {\n\t\topacity: {\n\t\t\tget: function( elem, computed ) {\n\t\t\t\tif ( computed ) {\n\n\t\t\t\t\t// We should always get a number back from opacity\n\t\t\t\t\tvar ret = curCSS( elem, \"opacity\" );\n\t\t\t\t\treturn ret === \"\" ? \"1\" : ret;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// Don't automatically add \"px\" to these possibly-unitless properties\n\tcssNumber: {\n\t\t\"animationIterationCount\": true,\n\t\t\"columnCount\": true,\n\t\t\"fillOpacity\": true,\n\t\t\"flexGrow\": true,\n\t\t\"flexShrink\": true,\n\t\t\"fontWeight\": true,\n\t\t\"lineHeight\": true,\n\t\t\"opacity\": true,\n\t\t\"order\": true,\n\t\t\"orphans\": true,\n\t\t\"widows\": true,\n\t\t\"zIndex\": true,\n\t\t\"zoom\": true\n\t},\n\n\t// Add in properties whose names you wish to fix before\n\t// setting or getting the value\n\tcssProps: {\n\t\t\"float\": \"cssFloat\"\n\t},\n\n\t// Get and set the style property on a DOM Node\n\tstyle: function( elem, name, value, extra ) {\n\n\t\t// Don't set styles on text and comment nodes\n\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make sure that we're working with the right name\n\t\tvar ret, type, hooks,\n\t\t\torigName = jQuery.camelCase( name ),\n\t\t\tstyle = elem.style;\n\n\t\tname = jQuery.cssProps[ origName ] ||\n\t\t\t( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName );\n\n\t\t// Gets hook for the prefixed version, then unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// Check if we're setting a value\n\t\tif ( value !== undefined ) {\n\t\t\ttype = typeof value;\n\n\t\t\t// Convert \"+=\" or \"-=\" to relative numbers (#7345)\n\t\t\tif ( type === \"string\" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {\n\t\t\t\tvalue = adjustCSS( elem, name, ret );\n\n\t\t\t\t// Fixes bug #9237\n\t\t\t\ttype = \"number\";\n\t\t\t}\n\n\t\t\t// Make sure that null and NaN values aren't set (#7116)\n\t\t\tif ( value == null || value !== value ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If a number was passed in, add the unit (except for certain CSS properties)\n\t\t\tif ( type === \"number\" ) {\n\t\t\t\tvalue += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? \"\" : \"px\" );\n\t\t\t}\n\n\t\t\t// Support: IE9-11+\n\t\t\t// background-* props affect original clone's values\n\t\t\tif ( !support.clearCloneStyle && value === \"\" && name.indexOf( \"background\" ) === 0 ) {\n\t\t\t\tstyle[ name ] = \"inherit\";\n\t\t\t}\n\n\t\t\t// If a hook was provided, use that value, otherwise just set the specified value\n\t\t\tif ( !hooks || !( \"set\" in hooks ) ||\n\t\t\t\t( value = hooks.set( elem, value, extra ) ) !== undefined ) {\n\n\t\t\t\tstyle[ name ] = value;\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// If a hook was provided get the non-computed value from there\n\t\t\tif ( hooks && \"get\" in hooks &&\n\t\t\t\t( ret = hooks.get( elem, false, extra ) ) !== undefined ) {\n\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\t// Otherwise just get the value from the style object\n\t\t\treturn style[ name ];\n\t\t}\n\t},\n\n\tcss: function( elem, name, extra, styles ) {\n\t\tvar val, num, hooks,\n\t\t\torigName = jQuery.camelCase( name );\n\n\t\t// Make sure that we're working with the right name\n\t\tname = jQuery.cssProps[ origName ] ||\n\t\t\t( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName );\n\n\t\t// Try prefixed name followed by the unprefixed name\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// If a hook was provided get the computed value from there\n\t\tif ( hooks && \"get\" in hooks ) {\n\t\t\tval = hooks.get( elem, true, extra );\n\t\t}\n\n\t\t// Otherwise, if a way to get the computed value exists, use that\n\t\tif ( val === undefined ) {\n\t\t\tval = curCSS( elem, name, styles );\n\t\t}\n\n\t\t// Convert \"normal\" to computed value\n\t\tif ( val === \"normal\" && name in cssNormalTransform ) {\n\t\t\tval = cssNormalTransform[ name ];\n\t\t}\n\n\t\t// Make numeric if forced or a qualifier was provided and val looks numeric\n\t\tif ( extra === \"\" || extra ) {\n\t\t\tnum = parseFloat( val );\n\t\t\treturn extra === true || isFinite( num ) ? num || 0 : val;\n\t\t}\n\t\treturn val;\n\t}\n} );\n\njQuery.each( [ \"height\", \"width\" ], function( i, name ) {\n\tjQuery.cssHooks[ name ] = {\n\t\tget: function( elem, computed, extra ) {\n\t\t\tif ( computed ) {\n\n\t\t\t\t// Certain elements can have dimension info if we invisibly show them\n\t\t\t\t// but it must have a current display style that would benefit\n\t\t\t\treturn rdisplayswap.test( jQuery.css( elem, \"display\" ) ) &&\n\t\t\t\t\telem.offsetWidth === 0 ?\n\t\t\t\t\t\tswap( elem, cssShow, function() {\n\t\t\t\t\t\t\treturn getWidthOrHeight( elem, name, extra );\n\t\t\t\t\t\t} ) :\n\t\t\t\t\t\tgetWidthOrHeight( elem, name, extra );\n\t\t\t}\n\t\t},\n\n\t\tset: function( elem, value, extra ) {\n\t\t\tvar matches,\n\t\t\t\tstyles = extra && getStyles( elem ),\n\t\t\t\tsubtract = extra && augmentWidthOrHeight(\n\t\t\t\t\telem,\n\t\t\t\t\tname,\n\t\t\t\t\textra,\n\t\t\t\t\tjQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\t\t\t\tstyles\n\t\t\t\t);\n\n\t\t\t// Convert to pixels if value adjustment is needed\n\t\t\tif ( subtract && ( matches = rcssNum.exec( value ) ) &&\n\t\t\t\t( matches[ 3 ] || \"px\" ) !== \"px\" ) {\n\n\t\t\t\telem.style[ name ] = value;\n\t\t\t\tvalue = jQuery.css( elem, name );\n\t\t\t}\n\n\t\t\treturn setPositiveNumber( elem, value, subtract );\n\t\t}\n\t};\n} );\n\njQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,\n\tfunction( elem, computed ) {\n\t\tif ( computed ) {\n\t\t\treturn ( parseFloat( curCSS( elem, \"marginLeft\" ) ) ||\n\t\t\t\telem.getBoundingClientRect().left -\n\t\t\t\t\tswap( elem, { marginLeft: 0 }, function() {\n\t\t\t\t\t\treturn elem.getBoundingClientRect().left;\n\t\t\t\t\t} )\n\t\t\t\t) + \"px\";\n\t\t}\n\t}\n);\n\n// Support: Android 2.3\njQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,\n\tfunction( elem, computed ) {\n\t\tif ( computed ) {\n\t\t\treturn swap( elem, { \"display\": \"inline-block\" },\n\t\t\t\tcurCSS, [ elem, \"marginRight\" ] );\n\t\t}\n\t}\n);\n\n// These hooks are used by animate to expand properties\njQuery.each( {\n\tmargin: \"\",\n\tpadding: \"\",\n\tborder: \"Width\"\n}, function( prefix, suffix ) {\n\tjQuery.cssHooks[ prefix + suffix ] = {\n\t\texpand: function( value ) {\n\t\t\tvar i = 0,\n\t\t\t\texpanded = {},\n\n\t\t\t\t// Assumes a single number if not a string\n\t\t\t\tparts = typeof value === \"string\" ? value.split( \" \" ) : [ value ];\n\n\t\t\tfor ( ; i < 4; i++ ) {\n\t\t\t\texpanded[ prefix + cssExpand[ i ] + suffix ] =\n\t\t\t\t\tparts[ i ] || parts[ i - 2 ] || parts[ 0 ];\n\t\t\t}\n\n\t\t\treturn expanded;\n\t\t}\n\t};\n\n\tif ( !rmargin.test( prefix ) ) {\n\t\tjQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;\n\t}\n} );\n\njQuery.fn.extend( {\n\tcss: function( name, value ) {\n\t\treturn access( this, function( elem, name, value ) {\n\t\t\tvar styles, len,\n\t\t\t\tmap = {},\n\t\t\t\ti = 0;\n\n\t\t\tif ( jQuery.isArray( name ) ) {\n\t\t\t\tstyles = getStyles( elem );\n\t\t\t\tlen = name.length;\n\n\t\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t\tmap[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );\n\t\t\t\t}\n\n\t\t\t\treturn map;\n\t\t\t}\n\n\t\t\treturn value !== undefined ?\n\t\t\t\tjQuery.style( elem, name, value ) :\n\t\t\t\tjQuery.css( elem, name );\n\t\t}, name, value, arguments.length > 1 );\n\t},\n\tshow: function() {\n\t\treturn showHide( this, true );\n\t},\n\thide: function() {\n\t\treturn showHide( this );\n\t},\n\ttoggle: function( state ) {\n\t\tif ( typeof state === \"boolean\" ) {\n\t\t\treturn state ? this.show() : this.hide();\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tif ( isHidden( this ) ) {\n\t\t\t\tjQuery( this ).show();\n\t\t\t} else {\n\t\t\t\tjQuery( this ).hide();\n\t\t\t}\n\t\t} );\n\t}\n} );\n\n\nfunction Tween( elem, options, prop, end, easing ) {\n\treturn new Tween.prototype.init( elem, options, prop, end, easing );\n}\njQuery.Tween = Tween;\n\nTween.prototype = {\n\tconstructor: Tween,\n\tinit: function( elem, options, prop, end, easing, unit ) {\n\t\tthis.elem = elem;\n\t\tthis.prop = prop;\n\t\tthis.easing = easing || jQuery.easing._default;\n\t\tthis.options = options;\n\t\tthis.start = this.now = this.cur();\n\t\tthis.end = end;\n\t\tthis.unit = unit || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" );\n\t},\n\tcur: function() {\n\t\tvar hooks = Tween.propHooks[ this.prop ];\n\n\t\treturn hooks && hooks.get ?\n\t\t\thooks.get( this ) :\n\t\t\tTween.propHooks._default.get( this );\n\t},\n\trun: function( percent ) {\n\t\tvar eased,\n\t\t\thooks = Tween.propHooks[ this.prop ];\n\n\t\tif ( this.options.duration ) {\n\t\t\tthis.pos = eased = jQuery.easing[ this.easing ](\n\t\t\t\tpercent, this.options.duration * percent, 0, 1, this.options.duration\n\t\t\t);\n\t\t} else {\n\t\t\tthis.pos = eased = percent;\n\t\t}\n\t\tthis.now = ( this.end - this.start ) * eased + this.start;\n\n\t\tif ( this.options.step ) {\n\t\t\tthis.options.step.call( this.elem, this.now, this );\n\t\t}\n\n\t\tif ( hooks && hooks.set ) {\n\t\t\thooks.set( this );\n\t\t} else {\n\t\t\tTween.propHooks._default.set( this );\n\t\t}\n\t\treturn this;\n\t}\n};\n\nTween.prototype.init.prototype = Tween.prototype;\n\nTween.propHooks = {\n\t_default: {\n\t\tget: function( tween ) {\n\t\t\tvar result;\n\n\t\t\t// Use a property on the element directly when it is not a DOM element,\n\t\t\t// or when there is no matching style property that exists.\n\t\t\tif ( tween.elem.nodeType !== 1 ||\n\t\t\t\ttween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {\n\t\t\t\treturn tween.elem[ tween.prop ];\n\t\t\t}\n\n\t\t\t// Passing an empty string as a 3rd parameter to .css will automatically\n\t\t\t// attempt a parseFloat and fallback to a string if the parse fails.\n\t\t\t// Simple values such as \"10px\" are parsed to Float;\n\t\t\t// complex values such as \"rotate(1rad)\" are returned as-is.\n\t\t\tresult = jQuery.css( tween.elem, tween.prop, \"\" );\n\n\t\t\t// Empty strings, null, undefined and \"auto\" are converted to 0.\n\t\t\treturn !result || result === \"auto\" ? 0 : result;\n\t\t},\n\t\tset: function( tween ) {\n\n\t\t\t// Use step hook for back compat.\n\t\t\t// Use cssHook if its there.\n\t\t\t// Use .style if available and use plain properties where available.\n\t\t\tif ( jQuery.fx.step[ tween.prop ] ) {\n\t\t\t\tjQuery.fx.step[ tween.prop ]( tween );\n\t\t\t} else if ( tween.elem.nodeType === 1 &&\n\t\t\t\t( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null ||\n\t\t\t\t\tjQuery.cssHooks[ tween.prop ] ) ) {\n\t\t\t\tjQuery.style( tween.elem, tween.prop, tween.now + tween.unit );\n\t\t\t} else {\n\t\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Support: IE9\n// Panic based approach to setting things on disconnected nodes\nTween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {\n\tset: function( tween ) {\n\t\tif ( tween.elem.nodeType && tween.elem.parentNode ) {\n\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t}\n\t}\n};\n\njQuery.easing = {\n\tlinear: function( p ) {\n\t\treturn p;\n\t},\n\tswing: function( p ) {\n\t\treturn 0.5 - Math.cos( p * Math.PI ) / 2;\n\t},\n\t_default: \"swing\"\n};\n\njQuery.fx = Tween.prototype.init;\n\n// Back Compat <1.8 extension point\njQuery.fx.step = {};\n\n\n\n\nvar\n\tfxNow, timerId,\n\trfxtypes = /^(?:toggle|show|hide)$/,\n\trrun = /queueHooks$/;\n\n// Animations created synchronously will run synchronously\nfunction createFxNow() {\n\twindow.setTimeout( function() {\n\t\tfxNow = undefined;\n\t} );\n\treturn ( fxNow = jQuery.now() );\n}\n\n// Generate parameters to create a standard animation\nfunction genFx( type, includeWidth ) {\n\tvar which,\n\t\ti = 0,\n\t\tattrs = { height: type };\n\n\t// If we include width, step value is 1 to do all cssExpand values,\n\t// otherwise step value is 2 to skip over Left and Right\n\tincludeWidth = includeWidth ? 1 : 0;\n\tfor ( ; i < 4 ; i += 2 - includeWidth ) {\n\t\twhich = cssExpand[ i ];\n\t\tattrs[ \"margin\" + which ] = attrs[ \"padding\" + which ] = type;\n\t}\n\n\tif ( includeWidth ) {\n\t\tattrs.opacity = attrs.width = type;\n\t}\n\n\treturn attrs;\n}\n\nfunction createTween( value, prop, animation ) {\n\tvar tween,\n\t\tcollection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ \"*\" ] ),\n\t\tindex = 0,\n\t\tlength = collection.length;\n\tfor ( ; index < length; index++ ) {\n\t\tif ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {\n\n\t\t\t// We're done with this property\n\t\t\treturn tween;\n\t\t}\n\t}\n}\n\nfunction defaultPrefilter( elem, props, opts ) {\n\t/* jshint validthis: true */\n\tvar prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,\n\t\tanim = this,\n\t\torig = {},\n\t\tstyle = elem.style,\n\t\thidden = elem.nodeType && isHidden( elem ),\n\t\tdataShow = dataPriv.get( elem, \"fxshow\" );\n\n\t// Handle queue: false promises\n\tif ( !opts.queue ) {\n\t\thooks = jQuery._queueHooks( elem, \"fx\" );\n\t\tif ( hooks.unqueued == null ) {\n\t\t\thooks.unqueued = 0;\n\t\t\toldfire = hooks.empty.fire;\n\t\t\thooks.empty.fire = function() {\n\t\t\t\tif ( !hooks.unqueued ) {\n\t\t\t\t\toldfire();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\thooks.unqueued++;\n\n\t\tanim.always( function() {\n\n\t\t\t// Ensure the complete handler is called before this completes\n\t\t\tanim.always( function() {\n\t\t\t\thooks.unqueued--;\n\t\t\t\tif ( !jQuery.queue( elem, \"fx\" ).length ) {\n\t\t\t\t\thooks.empty.fire();\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t}\n\n\t// Height/width overflow pass\n\tif ( elem.nodeType === 1 && ( \"height\" in props || \"width\" in props ) ) {\n\n\t\t// Make sure that nothing sneaks out\n\t\t// Record all 3 overflow attributes because IE9-10 do not\n\t\t// change the overflow attribute when overflowX and\n\t\t// overflowY are set to the same value\n\t\topts.overflow = [ style.overflow, style.overflowX, style.overflowY ];\n\n\t\t// Set display property to inline-block for height/width\n\t\t// animations on inline elements that are having width/height animated\n\t\tdisplay = jQuery.css( elem, \"display\" );\n\n\t\t// Test default display if display is currently \"none\"\n\t\tcheckDisplay = display === \"none\" ?\n\t\t\tdataPriv.get( elem, \"olddisplay\" ) || defaultDisplay( elem.nodeName ) : display;\n\n\t\tif ( checkDisplay === \"inline\" && jQuery.css( elem, \"float\" ) === \"none\" ) {\n\t\t\tstyle.display = \"inline-block\";\n\t\t}\n\t}\n\n\tif ( opts.overflow ) {\n\t\tstyle.overflow = \"hidden\";\n\t\tanim.always( function() {\n\t\t\tstyle.overflow = opts.overflow[ 0 ];\n\t\t\tstyle.overflowX = opts.overflow[ 1 ];\n\t\t\tstyle.overflowY = opts.overflow[ 2 ];\n\t\t} );\n\t}\n\n\t// show/hide pass\n\tfor ( prop in props ) {\n\t\tvalue = props[ prop ];\n\t\tif ( rfxtypes.exec( value ) ) {\n\t\t\tdelete props[ prop ];\n\t\t\ttoggle = toggle || value === \"toggle\";\n\t\t\tif ( value === ( hidden ? \"hide\" : \"show\" ) ) {\n\n\t\t\t\t// If there is dataShow left over from a stopped hide or show\n\t\t\t\t// and we are going to proceed with show, we should pretend to be hidden\n\t\t\t\tif ( value === \"show\" && dataShow && dataShow[ prop ] !== undefined ) {\n\t\t\t\t\thidden = true;\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\torig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );\n\n\t\t// Any non-fx value stops us from restoring the original display value\n\t\t} else {\n\t\t\tdisplay = undefined;\n\t\t}\n\t}\n\n\tif ( !jQuery.isEmptyObject( orig ) ) {\n\t\tif ( dataShow ) {\n\t\t\tif ( \"hidden\" in dataShow ) {\n\t\t\t\thidden = dataShow.hidden;\n\t\t\t}\n\t\t} else {\n\t\t\tdataShow = dataPriv.access( elem, \"fxshow\", {} );\n\t\t}\n\n\t\t// Store state if its toggle - enables .stop().toggle() to \"reverse\"\n\t\tif ( toggle ) {\n\t\t\tdataShow.hidden = !hidden;\n\t\t}\n\t\tif ( hidden ) {\n\t\t\tjQuery( elem ).show();\n\t\t} else {\n\t\t\tanim.done( function() {\n\t\t\t\tjQuery( elem ).hide();\n\t\t\t} );\n\t\t}\n\t\tanim.done( function() {\n\t\t\tvar prop;\n\n\t\t\tdataPriv.remove( elem, \"fxshow\" );\n\t\t\tfor ( prop in orig ) {\n\t\t\t\tjQuery.style( elem, prop, orig[ prop ] );\n\t\t\t}\n\t\t} );\n\t\tfor ( prop in orig ) {\n\t\t\ttween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );\n\n\t\t\tif ( !( prop in dataShow ) ) {\n\t\t\t\tdataShow[ prop ] = tween.start;\n\t\t\t\tif ( hidden ) {\n\t\t\t\t\ttween.end = tween.start;\n\t\t\t\t\ttween.start = prop === \"width\" || prop === \"height\" ? 1 : 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t// If this is a noop like .hide().hide(), restore an overwritten display value\n\t} else if ( ( display === \"none\" ? defaultDisplay( elem.nodeName ) : display ) === \"inline\" ) {\n\t\tstyle.display = display;\n\t}\n}\n\nfunction propFilter( props, specialEasing ) {\n\tvar index, name, easing, value, hooks;\n\n\t// camelCase, specialEasing and expand cssHook pass\n\tfor ( index in props ) {\n\t\tname = jQuery.camelCase( index );\n\t\teasing = specialEasing[ name ];\n\t\tvalue = props[ index ];\n\t\tif ( jQuery.isArray( value ) ) {\n\t\t\teasing = value[ 1 ];\n\t\t\tvalue = props[ index ] = value[ 0 ];\n\t\t}\n\n\t\tif ( index !== name ) {\n\t\t\tprops[ name ] = value;\n\t\t\tdelete props[ index ];\n\t\t}\n\n\t\thooks = jQuery.cssHooks[ name ];\n\t\tif ( hooks && \"expand\" in hooks ) {\n\t\t\tvalue = hooks.expand( value );\n\t\t\tdelete props[ name ];\n\n\t\t\t// Not quite $.extend, this won't overwrite existing keys.\n\t\t\t// Reusing 'index' because we have the correct \"name\"\n\t\t\tfor ( index in value ) {\n\t\t\t\tif ( !( index in props ) ) {\n\t\t\t\t\tprops[ index ] = value[ index ];\n\t\t\t\t\tspecialEasing[ index ] = easing;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tspecialEasing[ name ] = easing;\n\t\t}\n\t}\n}\n\nfunction Animation( elem, properties, options ) {\n\tvar result,\n\t\tstopped,\n\t\tindex = 0,\n\t\tlength = Animation.prefilters.length,\n\t\tdeferred = jQuery.Deferred().always( function() {\n\n\t\t\t// Don't match elem in the :animated selector\n\t\t\tdelete tick.elem;\n\t\t} ),\n\t\ttick = function() {\n\t\t\tif ( stopped ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar currentTime = fxNow || createFxNow(),\n\t\t\t\tremaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),\n\n\t\t\t\t// Support: Android 2.3\n\t\t\t\t// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)\n\t\t\t\ttemp = remaining / animation.duration || 0,\n\t\t\t\tpercent = 1 - temp,\n\t\t\t\tindex = 0,\n\t\t\t\tlength = animation.tweens.length;\n\n\t\t\tfor ( ; index < length ; index++ ) {\n\t\t\t\tanimation.tweens[ index ].run( percent );\n\t\t\t}\n\n\t\t\tdeferred.notifyWith( elem, [ animation, percent, remaining ] );\n\n\t\t\tif ( percent < 1 && length ) {\n\t\t\t\treturn remaining;\n\t\t\t} else {\n\t\t\t\tdeferred.resolveWith( elem, [ animation ] );\n\t\t\t\treturn false;\n\t\t\t}\n\t\t},\n\t\tanimation = deferred.promise( {\n\t\t\telem: elem,\n\t\t\tprops: jQuery.extend( {}, properties ),\n\t\t\topts: jQuery.extend( true, {\n\t\t\t\tspecialEasing: {},\n\t\t\t\teasing: jQuery.easing._default\n\t\t\t}, options ),\n\t\t\toriginalProperties: properties,\n\t\t\toriginalOptions: options,\n\t\t\tstartTime: fxNow || createFxNow(),\n\t\t\tduration: options.duration,\n\t\t\ttweens: [],\n\t\t\tcreateTween: function( prop, end ) {\n\t\t\t\tvar tween = jQuery.Tween( elem, animation.opts, prop, end,\n\t\t\t\t\t\tanimation.opts.specialEasing[ prop ] || animation.opts.easing );\n\t\t\t\tanimation.tweens.push( tween );\n\t\t\t\treturn tween;\n\t\t\t},\n\t\t\tstop: function( gotoEnd ) {\n\t\t\t\tvar index = 0,\n\n\t\t\t\t\t// If we are going to the end, we want to run all the tweens\n\t\t\t\t\t// otherwise we skip this part\n\t\t\t\t\tlength = gotoEnd ? animation.tweens.length : 0;\n\t\t\t\tif ( stopped ) {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t\tstopped = true;\n\t\t\t\tfor ( ; index < length ; index++ ) {\n\t\t\t\t\tanimation.tweens[ index ].run( 1 );\n\t\t\t\t}\n\n\t\t\t\t// Resolve when we played the last frame; otherwise, reject\n\t\t\t\tif ( gotoEnd ) {\n\t\t\t\t\tdeferred.notifyWith( elem, [ animation, 1, 0 ] );\n\t\t\t\t\tdeferred.resolveWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t} else {\n\t\t\t\t\tdeferred.rejectWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\t\t} ),\n\t\tprops = animation.props;\n\n\tpropFilter( props, animation.opts.specialEasing );\n\n\tfor ( ; index < length ; index++ ) {\n\t\tresult = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );\n\t\tif ( result ) {\n\t\t\tif ( jQuery.isFunction( result.stop ) ) {\n\t\t\t\tjQuery._queueHooks( animation.elem, animation.opts.queue ).stop =\n\t\t\t\t\tjQuery.proxy( result.stop, result );\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tjQuery.map( props, createTween, animation );\n\n\tif ( jQuery.isFunction( animation.opts.start ) ) {\n\t\tanimation.opts.start.call( elem, animation );\n\t}\n\n\tjQuery.fx.timer(\n\t\tjQuery.extend( tick, {\n\t\t\telem: elem,\n\t\t\tanim: animation,\n\t\t\tqueue: animation.opts.queue\n\t\t} )\n\t);\n\n\t// attach callbacks from options\n\treturn animation.progress( animation.opts.progress )\n\t\t.done( animation.opts.done, animation.opts.complete )\n\t\t.fail( animation.opts.fail )\n\t\t.always( animation.opts.always );\n}\n\njQuery.Animation = jQuery.extend( Animation, {\n\ttweeners: {\n\t\t\"*\": [ function( prop, value ) {\n\t\t\tvar tween = this.createTween( prop, value );\n\t\t\tadjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );\n\t\t\treturn tween;\n\t\t} ]\n\t},\n\n\ttweener: function( props, callback ) {\n\t\tif ( jQuery.isFunction( props ) ) {\n\t\t\tcallback = props;\n\t\t\tprops = [ \"*\" ];\n\t\t} else {\n\t\t\tprops = props.match( rnotwhite );\n\t\t}\n\n\t\tvar prop,\n\t\t\tindex = 0,\n\t\t\tlength = props.length;\n\n\t\tfor ( ; index < length ; index++ ) {\n\t\t\tprop = props[ index ];\n\t\t\tAnimation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];\n\t\t\tAnimation.tweeners[ prop ].unshift( callback );\n\t\t}\n\t},\n\n\tprefilters: [ defaultPrefilter ],\n\n\tprefilter: function( callback, prepend ) {\n\t\tif ( prepend ) {\n\t\t\tAnimation.prefilters.unshift( callback );\n\t\t} else {\n\t\t\tAnimation.prefilters.push( callback );\n\t\t}\n\t}\n} );\n\njQuery.speed = function( speed, easing, fn ) {\n\tvar opt = speed && typeof speed === \"object\" ? jQuery.extend( {}, speed ) : {\n\t\tcomplete: fn || !fn && easing ||\n\t\t\tjQuery.isFunction( speed ) && speed,\n\t\tduration: speed,\n\t\teasing: fn && easing || easing && !jQuery.isFunction( easing ) && easing\n\t};\n\n\topt.duration = jQuery.fx.off ? 0 : typeof opt.duration === \"number\" ?\n\t\topt.duration : opt.duration in jQuery.fx.speeds ?\n\t\t\tjQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;\n\n\t// Normalize opt.queue - true/undefined/null -> \"fx\"\n\tif ( opt.queue == null || opt.queue === true ) {\n\t\topt.queue = \"fx\";\n\t}\n\n\t// Queueing\n\topt.old = opt.complete;\n\n\topt.complete = function() {\n\t\tif ( jQuery.isFunction( opt.old ) ) {\n\t\t\topt.old.call( this );\n\t\t}\n\n\t\tif ( opt.queue ) {\n\t\t\tjQuery.dequeue( this, opt.queue );\n\t\t}\n\t};\n\n\treturn opt;\n};\n\njQuery.fn.extend( {\n\tfadeTo: function( speed, to, easing, callback ) {\n\n\t\t// Show any hidden elements after setting opacity to 0\n\t\treturn this.filter( isHidden ).css( \"opacity\", 0 ).show()\n\n\t\t\t// Animate to the value specified\n\t\t\t.end().animate( { opacity: to }, speed, easing, callback );\n\t},\n\tanimate: function( prop, speed, easing, callback ) {\n\t\tvar empty = jQuery.isEmptyObject( prop ),\n\t\t\toptall = jQuery.speed( speed, easing, callback ),\n\t\t\tdoAnimation = function() {\n\n\t\t\t\t// Operate on a copy of prop so per-property easing won't be lost\n\t\t\t\tvar anim = Animation( this, jQuery.extend( {}, prop ), optall );\n\n\t\t\t\t// Empty animations, or finishing resolves immediately\n\t\t\t\tif ( empty || dataPriv.get( this, \"finish\" ) ) {\n\t\t\t\t\tanim.stop( true );\n\t\t\t\t}\n\t\t\t};\n\t\t\tdoAnimation.finish = doAnimation;\n\n\t\treturn empty || optall.queue === false ?\n\t\t\tthis.each( doAnimation ) :\n\t\t\tthis.queue( optall.queue, doAnimation );\n\t},\n\tstop: function( type, clearQueue, gotoEnd ) {\n\t\tvar stopQueue = function( hooks ) {\n\t\t\tvar stop = hooks.stop;\n\t\t\tdelete hooks.stop;\n\t\t\tstop( gotoEnd );\n\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tgotoEnd = clearQueue;\n\t\t\tclearQueue = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\tif ( clearQueue && type !== false ) {\n\t\t\tthis.queue( type || \"fx\", [] );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar dequeue = true,\n\t\t\t\tindex = type != null && type + \"queueHooks\",\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tdata = dataPriv.get( this );\n\n\t\t\tif ( index ) {\n\t\t\t\tif ( data[ index ] && data[ index ].stop ) {\n\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( index in data ) {\n\t\t\t\t\tif ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {\n\t\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this &&\n\t\t\t\t\t( type == null || timers[ index ].queue === type ) ) {\n\n\t\t\t\t\ttimers[ index ].anim.stop( gotoEnd );\n\t\t\t\t\tdequeue = false;\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Start the next in the queue if the last step wasn't forced.\n\t\t\t// Timers currently will call their complete callbacks, which\n\t\t\t// will dequeue but only if they were gotoEnd.\n\t\t\tif ( dequeue || !gotoEnd ) {\n\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t}\n\t\t} );\n\t},\n\tfinish: function( type ) {\n\t\tif ( type !== false ) {\n\t\t\ttype = type || \"fx\";\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tvar index,\n\t\t\t\tdata = dataPriv.get( this ),\n\t\t\t\tqueue = data[ type + \"queue\" ],\n\t\t\t\thooks = data[ type + \"queueHooks\" ],\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tlength = queue ? queue.length : 0;\n\n\t\t\t// Enable finishing flag on private data\n\t\t\tdata.finish = true;\n\n\t\t\t// Empty the queue first\n\t\t\tjQuery.queue( this, type, [] );\n\n\t\t\tif ( hooks && hooks.stop ) {\n\t\t\t\thooks.stop.call( this, true );\n\t\t\t}\n\n\t\t\t// Look for any active animations, and finish them\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && timers[ index ].queue === type ) {\n\t\t\t\t\ttimers[ index ].anim.stop( true );\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Look for any animations in the old queue and finish them\n\t\t\tfor ( index = 0; index < length; index++ ) {\n\t\t\t\tif ( queue[ index ] && queue[ index ].finish ) {\n\t\t\t\t\tqueue[ index ].finish.call( this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Turn off finishing flag\n\t\t\tdelete data.finish;\n\t\t} );\n\t}\n} );\n\njQuery.each( [ \"toggle\", \"show\", \"hide\" ], function( i, name ) {\n\tvar cssFn = jQuery.fn[ name ];\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn speed == null || typeof speed === \"boolean\" ?\n\t\t\tcssFn.apply( this, arguments ) :\n\t\t\tthis.animate( genFx( name, true ), speed, easing, callback );\n\t};\n} );\n\n// Generate shortcuts for custom animations\njQuery.each( {\n\tslideDown: genFx( \"show\" ),\n\tslideUp: genFx( \"hide\" ),\n\tslideToggle: genFx( \"toggle\" ),\n\tfadeIn: { opacity: \"show\" },\n\tfadeOut: { opacity: \"hide\" },\n\tfadeToggle: { opacity: \"toggle\" }\n}, function( name, props ) {\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn this.animate( props, speed, easing, callback );\n\t};\n} );\n\njQuery.timers = [];\njQuery.fx.tick = function() {\n\tvar timer,\n\t\ti = 0,\n\t\ttimers = jQuery.timers;\n\n\tfxNow = jQuery.now();\n\n\tfor ( ; i < timers.length; i++ ) {\n\t\ttimer = timers[ i ];\n\n\t\t// Checks the timer has not already been removed\n\t\tif ( !timer() && timers[ i ] === timer ) {\n\t\t\ttimers.splice( i--, 1 );\n\t\t}\n\t}\n\n\tif ( !timers.length ) {\n\t\tjQuery.fx.stop();\n\t}\n\tfxNow = undefined;\n};\n\njQuery.fx.timer = function( timer ) {\n\tjQuery.timers.push( timer );\n\tif ( timer() ) {\n\t\tjQuery.fx.start();\n\t} else {\n\t\tjQuery.timers.pop();\n\t}\n};\n\njQuery.fx.interval = 13;\njQuery.fx.start = function() {\n\tif ( !timerId ) {\n\t\ttimerId = window.setInterval( jQuery.fx.tick, jQuery.fx.interval );\n\t}\n};\n\njQuery.fx.stop = function() {\n\twindow.clearInterval( timerId );\n\n\ttimerId = null;\n};\n\njQuery.fx.speeds = {\n\tslow: 600,\n\tfast: 200,\n\n\t// Default speed\n\t_default: 400\n};\n\n\n// Based off of the plugin by Clint Helfers, with permission.\n// http://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/\njQuery.fn.delay = function( time, type ) {\n\ttime = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n\ttype = type || \"fx\";\n\n\treturn this.queue( type, function( next, hooks ) {\n\t\tvar timeout = window.setTimeout( next, time );\n\t\thooks.stop = function() {\n\t\t\twindow.clearTimeout( timeout );\n\t\t};\n\t} );\n};\n\n\n( function() {\n\tvar input = document.createElement( \"input\" ),\n\t\tselect = document.createElement( \"select\" ),\n\t\topt = select.appendChild( document.createElement( \"option\" ) );\n\n\tinput.type = \"checkbox\";\n\n\t// Support: iOS<=5.1, Android<=4.2+\n\t// Default value for a checkbox should be \"on\"\n\tsupport.checkOn = input.value !== \"\";\n\n\t// Support: IE<=11+\n\t// Must access selectedIndex to make default options select\n\tsupport.optSelected = opt.selected;\n\n\t// Support: Android<=2.3\n\t// Options inside disabled selects are incorrectly marked as disabled\n\tselect.disabled = true;\n\tsupport.optDisabled = !opt.disabled;\n\n\t// Support: IE<=11+\n\t// An input loses its value after becoming a radio\n\tinput = document.createElement( \"input\" );\n\tinput.value = \"t\";\n\tinput.type = \"radio\";\n\tsupport.radioValue = input.value === \"t\";\n} )();\n\n\nvar boolHook,\n\tattrHandle = jQuery.expr.attrHandle;\n\njQuery.fn.extend( {\n\tattr: function( name, value ) {\n\t\treturn access( this, jQuery.attr, name, value, arguments.length > 1 );\n\t},\n\n\tremoveAttr: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.removeAttr( this, name );\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tattr: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set attributes on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Fallback to prop when attributes are not supported\n\t\tif ( typeof elem.getAttribute === \"undefined\" ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\t// All attributes are lowercase\n\t\t// Grab necessary hook if one is defined\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\t\t\tname = name.toLowerCase();\n\t\t\thooks = jQuery.attrHooks[ name ] ||\n\t\t\t\t( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( value === null ) {\n\t\t\t\tjQuery.removeAttr( elem, name );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\telem.setAttribute( name, value + \"\" );\n\t\t\treturn value;\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\tret = jQuery.find.attr( elem, name );\n\n\t\t// Non-existent attributes return null, we normalize to undefined\n\t\treturn ret == null ? undefined : ret;\n\t},\n\n\tattrHooks: {\n\t\ttype: {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tif ( !support.radioValue && value === \"radio\" &&\n\t\t\t\t\tjQuery.nodeName( elem, \"input\" ) ) {\n\t\t\t\t\tvar val = elem.value;\n\t\t\t\t\telem.setAttribute( \"type\", value );\n\t\t\t\t\tif ( val ) {\n\t\t\t\t\t\telem.value = val;\n\t\t\t\t\t}\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tremoveAttr: function( elem, value ) {\n\t\tvar name, propName,\n\t\t\ti = 0,\n\t\t\tattrNames = value && value.match( rnotwhite );\n\n\t\tif ( attrNames && elem.nodeType === 1 ) {\n\t\t\twhile ( ( name = attrNames[ i++ ] ) ) {\n\t\t\t\tpropName = jQuery.propFix[ name ] || name;\n\n\t\t\t\t// Boolean attributes get special treatment (#10870)\n\t\t\t\tif ( jQuery.expr.match.bool.test( name ) ) {\n\n\t\t\t\t\t// Set corresponding property to false\n\t\t\t\t\telem[ propName ] = false;\n\t\t\t\t}\n\n\t\t\t\telem.removeAttribute( name );\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Hooks for boolean attributes\nboolHook = {\n\tset: function( elem, value, name ) {\n\t\tif ( value === false ) {\n\n\t\t\t// Remove boolean attributes when set to false\n\t\t\tjQuery.removeAttr( elem, name );\n\t\t} else {\n\t\t\telem.setAttribute( name, name );\n\t\t}\n\t\treturn name;\n\t}\n};\njQuery.each( jQuery.expr.match.bool.source.match( /\\w+/g ), function( i, name ) {\n\tvar getter = attrHandle[ name ] || jQuery.find.attr;\n\n\tattrHandle[ name ] = function( elem, name, isXML ) {\n\t\tvar ret, handle;\n\t\tif ( !isXML ) {\n\n\t\t\t// Avoid an infinite loop by temporarily removing this function from the getter\n\t\t\thandle = attrHandle[ name ];\n\t\t\tattrHandle[ name ] = ret;\n\t\t\tret = getter( elem, name, isXML ) != null ?\n\t\t\t\tname.toLowerCase() :\n\t\t\t\tnull;\n\t\t\tattrHandle[ name ] = handle;\n\t\t}\n\t\treturn ret;\n\t};\n} );\n\n\n\n\nvar rfocusable = /^(?:input|select|textarea|button)$/i,\n\trclickable = /^(?:a|area)$/i;\n\njQuery.fn.extend( {\n\tprop: function( name, value ) {\n\t\treturn access( this, jQuery.prop, name, value, arguments.length > 1 );\n\t},\n\n\tremoveProp: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tdelete this[ jQuery.propFix[ name ] || name ];\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tprop: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set properties on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// Fix name and attach hooks\n\t\t\tname = jQuery.propFix[ name ] || name;\n\t\t\thooks = jQuery.propHooks[ name ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\treturn ( elem[ name ] = value );\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\treturn elem[ name ];\n\t},\n\n\tpropHooks: {\n\t\ttabIndex: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\t// elem.tabIndex doesn't always return the\n\t\t\t\t// correct value when it hasn't been explicitly set\n\t\t\t\t// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/\n\t\t\t\t// Use proper attribute retrieval(#12072)\n\t\t\t\tvar tabindex = jQuery.find.attr( elem, \"tabindex\" );\n\n\t\t\t\treturn tabindex ?\n\t\t\t\t\tparseInt( tabindex, 10 ) :\n\t\t\t\t\trfocusable.test( elem.nodeName ) ||\n\t\t\t\t\t\trclickable.test( elem.nodeName ) && elem.href ?\n\t\t\t\t\t\t\t0 :\n\t\t\t\t\t\t\t-1;\n\t\t\t}\n\t\t}\n\t},\n\n\tpropFix: {\n\t\t\"for\": \"htmlFor\",\n\t\t\"class\": \"className\"\n\t}\n} );\n\n// Support: IE <=11 only\n// Accessing the selectedIndex property\n// forces the browser to respect setting selected\n// on the option\n// The getter ensures a default option is selected\n// when in an optgroup\nif ( !support.optSelected ) {\n\tjQuery.propHooks.selected = {\n\t\tget: function( elem ) {\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent && parent.parentNode ) {\n\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\tset: function( elem ) {\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent ) {\n\t\t\t\tparent.selectedIndex;\n\n\t\t\t\tif ( parent.parentNode ) {\n\t\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\njQuery.each( [\n\t\"tabIndex\",\n\t\"readOnly\",\n\t\"maxLength\",\n\t\"cellSpacing\",\n\t\"cellPadding\",\n\t\"rowSpan\",\n\t\"colSpan\",\n\t\"useMap\",\n\t\"frameBorder\",\n\t\"contentEditable\"\n], function() {\n\tjQuery.propFix[ this.toLowerCase() ] = this;\n} );\n\n\n\n\nvar rclass = /[\\t\\r\\n\\f]/g;\n\nfunction getClass( elem ) {\n\treturn elem.getAttribute && elem.getAttribute( \"class\" ) || \"\";\n}\n\njQuery.fn.extend( {\n\taddClass: function( value ) {\n\t\tvar classes, elem, cur, curValue, clazz, j, finalValue,\n\t\t\ti = 0;\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).addClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tif ( typeof value === \"string\" && value ) {\n\t\t\tclasses = value.match( rnotwhite ) || [];\n\n\t\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\t\tcurValue = getClass( elem );\n\t\t\t\tcur = elem.nodeType === 1 &&\n\t\t\t\t\t( \" \" + curValue + \" \" ).replace( rclass, \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( ( clazz = classes[ j++ ] ) ) {\n\t\t\t\t\t\tif ( cur.indexOf( \" \" + clazz + \" \" ) < 0 ) {\n\t\t\t\t\t\t\tcur += clazz + \" \";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = jQuery.trim( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\telem.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tremoveClass: function( value ) {\n\t\tvar classes, elem, cur, curValue, clazz, j, finalValue,\n\t\t\ti = 0;\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tif ( !arguments.length ) {\n\t\t\treturn this.attr( \"class\", \"\" );\n\t\t}\n\n\t\tif ( typeof value === \"string\" && value ) {\n\t\t\tclasses = value.match( rnotwhite ) || [];\n\n\t\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\t\tcurValue = getClass( elem );\n\n\t\t\t\t// This expression is here for better compressibility (see addClass)\n\t\t\t\tcur = elem.nodeType === 1 &&\n\t\t\t\t\t( \" \" + curValue + \" \" ).replace( rclass, \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( ( clazz = classes[ j++ ] ) ) {\n\n\t\t\t\t\t\t// Remove *all* instances\n\t\t\t\t\t\twhile ( cur.indexOf( \" \" + clazz + \" \" ) > -1 ) {\n\t\t\t\t\t\t\tcur = cur.replace( \" \" + clazz + \" \", \" \" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = jQuery.trim( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\telem.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\ttoggleClass: function( value, stateVal ) {\n\t\tvar type = typeof value;\n\n\t\tif ( typeof stateVal === \"boolean\" && type === \"string\" ) {\n\t\t\treturn stateVal ? this.addClass( value ) : this.removeClass( value );\n\t\t}\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).toggleClass(\n\t\t\t\t\tvalue.call( this, i, getClass( this ), stateVal ),\n\t\t\t\t\tstateVal\n\t\t\t\t);\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar className, i, self, classNames;\n\n\t\t\tif ( type === \"string\" ) {\n\n\t\t\t\t// Toggle individual class names\n\t\t\t\ti = 0;\n\t\t\t\tself = jQuery( this );\n\t\t\t\tclassNames = value.match( rnotwhite ) || [];\n\n\t\t\t\twhile ( ( className = classNames[ i++ ] ) ) {\n\n\t\t\t\t\t// Check each className given, space separated list\n\t\t\t\t\tif ( self.hasClass( className ) ) {\n\t\t\t\t\t\tself.removeClass( className );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tself.addClass( className );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// Toggle whole class name\n\t\t\t} else if ( value === undefined || type === \"boolean\" ) {\n\t\t\t\tclassName = getClass( this );\n\t\t\t\tif ( className ) {\n\n\t\t\t\t\t// Store className if set\n\t\t\t\t\tdataPriv.set( this, \"__className__\", className );\n\t\t\t\t}\n\n\t\t\t\t// If the element has a class name or if we're passed `false`,\n\t\t\t\t// then remove the whole classname (if there was one, the above saved it).\n\t\t\t\t// Otherwise bring back whatever was previously saved (if anything),\n\t\t\t\t// falling back to the empty string if nothing was stored.\n\t\t\t\tif ( this.setAttribute ) {\n\t\t\t\t\tthis.setAttribute( \"class\",\n\t\t\t\t\t\tclassName || value === false ?\n\t\t\t\t\t\t\"\" :\n\t\t\t\t\t\tdataPriv.get( this, \"__className__\" ) || \"\"\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\thasClass: function( selector ) {\n\t\tvar className, elem,\n\t\t\ti = 0;\n\n\t\tclassName = \" \" + selector + \" \";\n\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\tif ( elem.nodeType === 1 &&\n\t\t\t\t( \" \" + getClass( elem ) + \" \" ).replace( rclass, \" \" )\n\t\t\t\t\t.indexOf( className ) > -1\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n} );\n\n\n\n\nvar rreturn = /\\r/g,\n\trspaces = /[\\x20\\t\\r\\n\\f]+/g;\n\njQuery.fn.extend( {\n\tval: function( value ) {\n\t\tvar hooks, ret, isFunction,\n\t\t\telem = this[ 0 ];\n\n\t\tif ( !arguments.length ) {\n\t\t\tif ( elem ) {\n\t\t\t\thooks = jQuery.valHooks[ elem.type ] ||\n\t\t\t\t\tjQuery.valHooks[ elem.nodeName.toLowerCase() ];\n\n\t\t\t\tif ( hooks &&\n\t\t\t\t\t\"get\" in hooks &&\n\t\t\t\t\t( ret = hooks.get( elem, \"value\" ) ) !== undefined\n\t\t\t\t) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\n\t\t\t\tret = elem.value;\n\n\t\t\t\treturn typeof ret === \"string\" ?\n\n\t\t\t\t\t// Handle most common string cases\n\t\t\t\t\tret.replace( rreturn, \"\" ) :\n\n\t\t\t\t\t// Handle cases where value is null/undef or number\n\t\t\t\t\tret == null ? \"\" : ret;\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tisFunction = jQuery.isFunction( value );\n\n\t\treturn this.each( function( i ) {\n\t\t\tvar val;\n\n\t\t\tif ( this.nodeType !== 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( isFunction ) {\n\t\t\t\tval = value.call( this, i, jQuery( this ).val() );\n\t\t\t} else {\n\t\t\t\tval = value;\n\t\t\t}\n\n\t\t\t// Treat null/undefined as \"\"; convert numbers to string\n\t\t\tif ( val == null ) {\n\t\t\t\tval = \"\";\n\n\t\t\t} else if ( typeof val === \"number\" ) {\n\t\t\t\tval += \"\";\n\n\t\t\t} else if ( jQuery.isArray( val ) ) {\n\t\t\t\tval = jQuery.map( val, function( value ) {\n\t\t\t\t\treturn value == null ? \"\" : value + \"\";\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\thooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];\n\n\t\t\t// If set returns undefined, fall back to normal setting\n\t\t\tif ( !hooks || !( \"set\" in hooks ) || hooks.set( this, val, \"value\" ) === undefined ) {\n\t\t\t\tthis.value = val;\n\t\t\t}\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tvalHooks: {\n\t\toption: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\tvar val = jQuery.find.attr( elem, \"value\" );\n\t\t\t\treturn val != null ?\n\t\t\t\t\tval :\n\n\t\t\t\t\t// Support: IE10-11+\n\t\t\t\t\t// option.text throws exceptions (#14686, #14858)\n\t\t\t\t\t// Strip and collapse whitespace\n\t\t\t\t\t// https://html.spec.whatwg.org/#strip-and-collapse-whitespace\n\t\t\t\t\tjQuery.trim( jQuery.text( elem ) ).replace( rspaces, \" \" );\n\t\t\t}\n\t\t},\n\t\tselect: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar value, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tindex = elem.selectedIndex,\n\t\t\t\t\tone = elem.type === \"select-one\" || index < 0,\n\t\t\t\t\tvalues = one ? null : [],\n\t\t\t\t\tmax = one ? index + 1 : options.length,\n\t\t\t\t\ti = index < 0 ?\n\t\t\t\t\t\tmax :\n\t\t\t\t\t\tone ? index : 0;\n\n\t\t\t\t// Loop through all the selected options\n\t\t\t\tfor ( ; i < max; i++ ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t// IE8-9 doesn't update selected after form reset (#2551)\n\t\t\t\t\tif ( ( option.selected || i === index ) &&\n\n\t\t\t\t\t\t\t// Don't return options that are disabled or in a disabled optgroup\n\t\t\t\t\t\t\t( support.optDisabled ?\n\t\t\t\t\t\t\t\t!option.disabled : option.getAttribute( \"disabled\" ) === null ) &&\n\t\t\t\t\t\t\t( !option.parentNode.disabled ||\n\t\t\t\t\t\t\t\t!jQuery.nodeName( option.parentNode, \"optgroup\" ) ) ) {\n\n\t\t\t\t\t\t// Get the specific value for the option\n\t\t\t\t\t\tvalue = jQuery( option ).val();\n\n\t\t\t\t\t\t// We don't need an array for one selects\n\t\t\t\t\t\tif ( one ) {\n\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Multi-Selects return an array\n\t\t\t\t\t\tvalues.push( value );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn values;\n\t\t\t},\n\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar optionSet, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tvalues = jQuery.makeArray( value ),\n\t\t\t\t\ti = options.length;\n\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\toption = options[ i ];\n\t\t\t\t\tif ( option.selected =\n\t\t\t\t\t\tjQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1\n\t\t\t\t\t) {\n\t\t\t\t\t\toptionSet = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Force browsers to behave consistently when non-matching value is set\n\t\t\t\tif ( !optionSet ) {\n\t\t\t\t\telem.selectedIndex = -1;\n\t\t\t\t}\n\t\t\t\treturn values;\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Radios and checkboxes getter/setter\njQuery.each( [ \"radio\", \"checkbox\" ], function() {\n\tjQuery.valHooks[ this ] = {\n\t\tset: function( elem, value ) {\n\t\t\tif ( jQuery.isArray( value ) ) {\n\t\t\t\treturn ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );\n\t\t\t}\n\t\t}\n\t};\n\tif ( !support.checkOn ) {\n\t\tjQuery.valHooks[ this ].get = function( elem ) {\n\t\t\treturn elem.getAttribute( \"value\" ) === null ? \"on\" : elem.value;\n\t\t};\n\t}\n} );\n\n\n\n\n// Return jQuery for attributes-only inclusion\n\n\nvar rfocusMorph = /^(?:focusinfocus|focusoutblur)$/;\n\njQuery.extend( jQuery.event, {\n\n\ttrigger: function( event, data, elem, onlyHandlers ) {\n\n\t\tvar i, cur, tmp, bubbleType, ontype, handle, special,\n\t\t\teventPath = [ elem || document ],\n\t\t\ttype = hasOwn.call( event, \"type\" ) ? event.type : event,\n\t\t\tnamespaces = hasOwn.call( event, \"namespace\" ) ? event.namespace.split( \".\" ) : [];\n\n\t\tcur = tmp = elem = elem || document;\n\n\t\t// Don't do events on text and comment nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// focus/blur morphs to focusin/out; ensure we're not firing them right now\n\t\tif ( rfocusMorph.test( type + jQuery.event.triggered ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( type.indexOf( \".\" ) > -1 ) {\n\n\t\t\t// Namespaced trigger; create a regexp to match event type in handle()\n\t\t\tnamespaces = type.split( \".\" );\n\t\t\ttype = namespaces.shift();\n\t\t\tnamespaces.sort();\n\t\t}\n\t\tontype = type.indexOf( \":\" ) < 0 && \"on\" + type;\n\n\t\t// Caller can pass in a jQuery.Event object, Object, or just an event type string\n\t\tevent = event[ jQuery.expando ] ?\n\t\t\tevent :\n\t\t\tnew jQuery.Event( type, typeof event === \"object\" && event );\n\n\t\t// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)\n\t\tevent.isTrigger = onlyHandlers ? 2 : 3;\n\t\tevent.namespace = namespaces.join( \".\" );\n\t\tevent.rnamespace = event.namespace ?\n\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" ) :\n\t\t\tnull;\n\n\t\t// Clean up the event in case it is being reused\n\t\tevent.result = undefined;\n\t\tif ( !event.target ) {\n\t\t\tevent.target = elem;\n\t\t}\n\n\t\t// Clone any incoming data and prepend the event, creating the handler arg list\n\t\tdata = data == null ?\n\t\t\t[ event ] :\n\t\t\tjQuery.makeArray( data, [ event ] );\n\n\t\t// Allow special events to draw outside the lines\n\t\tspecial = jQuery.event.special[ type ] || {};\n\t\tif ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine event propagation path in advance, per W3C events spec (#9951)\n\t\t// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)\n\t\tif ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {\n\n\t\t\tbubbleType = special.delegateType || type;\n\t\t\tif ( !rfocusMorph.test( bubbleType + type ) ) {\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t\tfor ( ; cur; cur = cur.parentNode ) {\n\t\t\t\teventPath.push( cur );\n\t\t\t\ttmp = cur;\n\t\t\t}\n\n\t\t\t// Only add window if we got to document (e.g., not plain obj or detached DOM)\n\t\t\tif ( tmp === ( elem.ownerDocument || document ) ) {\n\t\t\t\teventPath.push( tmp.defaultView || tmp.parentWindow || window );\n\t\t\t}\n\t\t}\n\n\t\t// Fire handlers on the event path\n\t\ti = 0;\n\t\twhile ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {\n\n\t\t\tevent.type = i > 1 ?\n\t\t\t\tbubbleType :\n\t\t\t\tspecial.bindType || type;\n\n\t\t\t// jQuery handler\n\t\t\thandle = ( dataPriv.get( cur, \"events\" ) || {} )[ event.type ] &&\n\t\t\t\tdataPriv.get( cur, \"handle\" );\n\t\t\tif ( handle ) {\n\t\t\t\thandle.apply( cur, data );\n\t\t\t}\n\n\t\t\t// Native handler\n\t\t\thandle = ontype && cur[ ontype ];\n\t\t\tif ( handle && handle.apply && acceptData( cur ) ) {\n\t\t\t\tevent.result = handle.apply( cur, data );\n\t\t\t\tif ( event.result === false ) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tevent.type = type;\n\n\t\t// If nobody prevented the default action, do it now\n\t\tif ( !onlyHandlers && !event.isDefaultPrevented() ) {\n\n\t\t\tif ( ( !special._default ||\n\t\t\t\tspecial._default.apply( eventPath.pop(), data ) === false ) &&\n\t\t\t\tacceptData( elem ) ) {\n\n\t\t\t\t// Call a native DOM method on the target with the same name name as the event.\n\t\t\t\t// Don't do default actions on window, that's where global variables be (#6170)\n\t\t\t\tif ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {\n\n\t\t\t\t\t// Don't re-trigger an onFOO event when we call its FOO() method\n\t\t\t\t\ttmp = elem[ ontype ];\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prevent re-triggering of the same event, since we already bubbled it above\n\t\t\t\t\tjQuery.event.triggered = type;\n\t\t\t\t\telem[ type ]();\n\t\t\t\t\tjQuery.event.triggered = undefined;\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = tmp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\t// Piggyback on a donor event to simulate a different one\n\tsimulate: function( type, elem, event ) {\n\t\tvar e = jQuery.extend(\n\t\t\tnew jQuery.Event(),\n\t\t\tevent,\n\t\t\t{\n\t\t\t\ttype: type,\n\t\t\t\tisSimulated: true\n\n\t\t\t\t// Previously, `originalEvent: {}` was set here, so stopPropagation call\n\t\t\t\t// would not be triggered on donor event, since in our own\n\t\t\t\t// jQuery.event.stopPropagation function we had a check for existence of\n\t\t\t\t// originalEvent.stopPropagation method, so, consequently it would be a noop.\n\t\t\t\t//\n\t\t\t\t// But now, this \"simulate\" function is used only for events\n\t\t\t\t// for which stopPropagation() is noop, so there is no need for that anymore.\n\t\t\t\t//\n\t\t\t\t// For the 1.x branch though, guard for \"click\" and \"submit\"\n\t\t\t\t// events is still used, but was moved to jQuery.event.stopPropagation function\n\t\t\t\t// because `originalEvent` should point to the original event for the constancy\n\t\t\t\t// with other events and for more focused logic\n\t\t\t}\n\t\t);\n\n\t\tjQuery.event.trigger( e, null, elem );\n\n\t\tif ( e.isDefaultPrevented() ) {\n\t\t\tevent.preventDefault();\n\t\t}\n\t}\n\n} );\n\njQuery.fn.extend( {\n\n\ttrigger: function( type, data ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.trigger( type, data, this );\n\t\t} );\n\t},\n\ttriggerHandler: function( type, data ) {\n\t\tvar elem = this[ 0 ];\n\t\tif ( elem ) {\n\t\t\treturn jQuery.event.trigger( type, data, elem, true );\n\t\t}\n\t}\n} );\n\n\njQuery.each( ( \"blur focus focusin focusout load resize scroll unload click dblclick \" +\n\t\"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave \" +\n\t\"change select submit keydown keypress keyup error contextmenu\" ).split( \" \" ),\n\tfunction( i, name ) {\n\n\t// Handle event binding\n\tjQuery.fn[ name ] = function( data, fn ) {\n\t\treturn arguments.length > 0 ?\n\t\t\tthis.on( name, null, data, fn ) :\n\t\t\tthis.trigger( name );\n\t};\n} );\n\njQuery.fn.extend( {\n\thover: function( fnOver, fnOut ) {\n\t\treturn this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n\t}\n} );\n\n\n\n\nsupport.focusin = \"onfocusin\" in window;\n\n\n// Support: Firefox\n// Firefox doesn't have focus(in | out) events\n// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787\n//\n// Support: Chrome, Safari\n// focus(in | out) events fire after focus & blur events,\n// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order\n// Related ticket - https://code.google.com/p/chromium/issues/detail?id=449857\nif ( !support.focusin ) {\n\tjQuery.each( { focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n\t\t// Attach a single capturing handler on the document while someone wants focusin/focusout\n\t\tvar handler = function( event ) {\n\t\t\tjQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );\n\t\t};\n\n\t\tjQuery.event.special[ fix ] = {\n\t\t\tsetup: function() {\n\t\t\t\tvar doc = this.ownerDocument || this,\n\t\t\t\t\tattaches = dataPriv.access( doc, fix );\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.addEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t\tdataPriv.access( doc, fix, ( attaches || 0 ) + 1 );\n\t\t\t},\n\t\t\tteardown: function() {\n\t\t\t\tvar doc = this.ownerDocument || this,\n\t\t\t\t\tattaches = dataPriv.access( doc, fix ) - 1;\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.removeEventListener( orig, handler, true );\n\t\t\t\t\tdataPriv.remove( doc, fix );\n\n\t\t\t\t} else {\n\t\t\t\t\tdataPriv.access( doc, fix, attaches );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t} );\n}\nvar location = window.location;\n\nvar nonce = jQuery.now();\n\nvar rquery = ( /\\?/ );\n\n\n\n// Support: Android 2.3\n// Workaround failure to string-cast null input\njQuery.parseJSON = function( data ) {\n\treturn JSON.parse( data + \"\" );\n};\n\n\n// Cross-browser xml parsing\njQuery.parseXML = function( data ) {\n\tvar xml;\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\n\t// Support: IE9\n\ttry {\n\t\txml = ( new window.DOMParser() ).parseFromString( data, \"text/xml\" );\n\t} catch ( e ) {\n\t\txml = undefined;\n\t}\n\n\tif ( !xml || xml.getElementsByTagName( \"parsererror\" ).length ) {\n\t\tjQuery.error( \"Invalid XML: \" + data );\n\t}\n\treturn xml;\n};\n\n\nvar\n\trhash = /#.*$/,\n\trts = /([?&])_=[^&]*/,\n\trheaders = /^(.*?):[ \\t]*([^\\r\\n]*)$/mg,\n\n\t// #7653, #8125, #8152: local protocol detection\n\trlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,\n\trnoContent = /^(?:GET|HEAD)$/,\n\trprotocol = /^\\/\\//,\n\n\t/* Prefilters\n\t * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)\n\t * 2) These are called:\n\t *    - BEFORE asking for a transport\n\t *    - AFTER param serialization (s.data is a string if s.processData is true)\n\t * 3) key is the dataType\n\t * 4) the catchall symbol \"*\" can be used\n\t * 5) execution will start with transport dataType and THEN continue down to \"*\" if needed\n\t */\n\tprefilters = {},\n\n\t/* Transports bindings\n\t * 1) key is the dataType\n\t * 2) the catchall symbol \"*\" can be used\n\t * 3) selection will start with transport dataType and THEN go to \"*\" if needed\n\t */\n\ttransports = {},\n\n\t// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression\n\tallTypes = \"*/\".concat( \"*\" ),\n\n\t// Anchor tag for parsing the document origin\n\toriginAnchor = document.createElement( \"a\" );\n\toriginAnchor.href = location.href;\n\n// Base \"constructor\" for jQuery.ajaxPrefilter and jQuery.ajaxTransport\nfunction addToPrefiltersOrTransports( structure ) {\n\n\t// dataTypeExpression is optional and defaults to \"*\"\n\treturn function( dataTypeExpression, func ) {\n\n\t\tif ( typeof dataTypeExpression !== \"string\" ) {\n\t\t\tfunc = dataTypeExpression;\n\t\t\tdataTypeExpression = \"*\";\n\t\t}\n\n\t\tvar dataType,\n\t\t\ti = 0,\n\t\t\tdataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];\n\n\t\tif ( jQuery.isFunction( func ) ) {\n\n\t\t\t// For each dataType in the dataTypeExpression\n\t\t\twhile ( ( dataType = dataTypes[ i++ ] ) ) {\n\n\t\t\t\t// Prepend if requested\n\t\t\t\tif ( dataType[ 0 ] === \"+\" ) {\n\t\t\t\t\tdataType = dataType.slice( 1 ) || \"*\";\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );\n\n\t\t\t\t// Otherwise append\n\t\t\t\t} else {\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).push( func );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Base inspection function for prefilters and transports\nfunction inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {\n\n\tvar inspected = {},\n\t\tseekingTransport = ( structure === transports );\n\n\tfunction inspect( dataType ) {\n\t\tvar selected;\n\t\tinspected[ dataType ] = true;\n\t\tjQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {\n\t\t\tvar dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );\n\t\t\tif ( typeof dataTypeOrTransport === \"string\" &&\n\t\t\t\t!seekingTransport && !inspected[ dataTypeOrTransport ] ) {\n\n\t\t\t\toptions.dataTypes.unshift( dataTypeOrTransport );\n\t\t\t\tinspect( dataTypeOrTransport );\n\t\t\t\treturn false;\n\t\t\t} else if ( seekingTransport ) {\n\t\t\t\treturn !( selected = dataTypeOrTransport );\n\t\t\t}\n\t\t} );\n\t\treturn selected;\n\t}\n\n\treturn inspect( options.dataTypes[ 0 ] ) || !inspected[ \"*\" ] && inspect( \"*\" );\n}\n\n// A special extend for ajax options\n// that takes \"flat\" options (not to be deep extended)\n// Fixes #9887\nfunction ajaxExtend( target, src ) {\n\tvar key, deep,\n\t\tflatOptions = jQuery.ajaxSettings.flatOptions || {};\n\n\tfor ( key in src ) {\n\t\tif ( src[ key ] !== undefined ) {\n\t\t\t( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];\n\t\t}\n\t}\n\tif ( deep ) {\n\t\tjQuery.extend( true, target, deep );\n\t}\n\n\treturn target;\n}\n\n/* Handles responses to an ajax request:\n * - finds the right dataType (mediates between content-type and expected dataType)\n * - returns the corresponding response\n */\nfunction ajaxHandleResponses( s, jqXHR, responses ) {\n\n\tvar ct, type, finalDataType, firstDataType,\n\t\tcontents = s.contents,\n\t\tdataTypes = s.dataTypes;\n\n\t// Remove auto dataType and get content-type in the process\n\twhile ( dataTypes[ 0 ] === \"*\" ) {\n\t\tdataTypes.shift();\n\t\tif ( ct === undefined ) {\n\t\t\tct = s.mimeType || jqXHR.getResponseHeader( \"Content-Type\" );\n\t\t}\n\t}\n\n\t// Check if we're dealing with a known content-type\n\tif ( ct ) {\n\t\tfor ( type in contents ) {\n\t\t\tif ( contents[ type ] && contents[ type ].test( ct ) ) {\n\t\t\t\tdataTypes.unshift( type );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check to see if we have a response for the expected dataType\n\tif ( dataTypes[ 0 ] in responses ) {\n\t\tfinalDataType = dataTypes[ 0 ];\n\t} else {\n\n\t\t// Try convertible dataTypes\n\t\tfor ( type in responses ) {\n\t\t\tif ( !dataTypes[ 0 ] || s.converters[ type + \" \" + dataTypes[ 0 ] ] ) {\n\t\t\t\tfinalDataType = type;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !firstDataType ) {\n\t\t\t\tfirstDataType = type;\n\t\t\t}\n\t\t}\n\n\t\t// Or just use first one\n\t\tfinalDataType = finalDataType || firstDataType;\n\t}\n\n\t// If we found a dataType\n\t// We add the dataType to the list if needed\n\t// and return the corresponding response\n\tif ( finalDataType ) {\n\t\tif ( finalDataType !== dataTypes[ 0 ] ) {\n\t\t\tdataTypes.unshift( finalDataType );\n\t\t}\n\t\treturn responses[ finalDataType ];\n\t}\n}\n\n/* Chain conversions given the request and the original response\n * Also sets the responseXXX fields on the jqXHR instance\n */\nfunction ajaxConvert( s, response, jqXHR, isSuccess ) {\n\tvar conv2, current, conv, tmp, prev,\n\t\tconverters = {},\n\n\t\t// Work with a copy of dataTypes in case we need to modify it for conversion\n\t\tdataTypes = s.dataTypes.slice();\n\n\t// Create converters map with lowercased keys\n\tif ( dataTypes[ 1 ] ) {\n\t\tfor ( conv in s.converters ) {\n\t\t\tconverters[ conv.toLowerCase() ] = s.converters[ conv ];\n\t\t}\n\t}\n\n\tcurrent = dataTypes.shift();\n\n\t// Convert to each sequential dataType\n\twhile ( current ) {\n\n\t\tif ( s.responseFields[ current ] ) {\n\t\t\tjqXHR[ s.responseFields[ current ] ] = response;\n\t\t}\n\n\t\t// Apply the dataFilter if provided\n\t\tif ( !prev && isSuccess && s.dataFilter ) {\n\t\t\tresponse = s.dataFilter( response, s.dataType );\n\t\t}\n\n\t\tprev = current;\n\t\tcurrent = dataTypes.shift();\n\n\t\tif ( current ) {\n\n\t\t// There's only work to do if current dataType is non-auto\n\t\t\tif ( current === \"*\" ) {\n\n\t\t\t\tcurrent = prev;\n\n\t\t\t// Convert response if prev dataType is non-auto and differs from current\n\t\t\t} else if ( prev !== \"*\" && prev !== current ) {\n\n\t\t\t\t// Seek a direct converter\n\t\t\t\tconv = converters[ prev + \" \" + current ] || converters[ \"* \" + current ];\n\n\t\t\t\t// If none found, seek a pair\n\t\t\t\tif ( !conv ) {\n\t\t\t\t\tfor ( conv2 in converters ) {\n\n\t\t\t\t\t\t// If conv2 outputs current\n\t\t\t\t\t\ttmp = conv2.split( \" \" );\n\t\t\t\t\t\tif ( tmp[ 1 ] === current ) {\n\n\t\t\t\t\t\t\t// If prev can be converted to accepted input\n\t\t\t\t\t\t\tconv = converters[ prev + \" \" + tmp[ 0 ] ] ||\n\t\t\t\t\t\t\t\tconverters[ \"* \" + tmp[ 0 ] ];\n\t\t\t\t\t\t\tif ( conv ) {\n\n\t\t\t\t\t\t\t\t// Condense equivalence converters\n\t\t\t\t\t\t\t\tif ( conv === true ) {\n\t\t\t\t\t\t\t\t\tconv = converters[ conv2 ];\n\n\t\t\t\t\t\t\t\t// Otherwise, insert the intermediate dataType\n\t\t\t\t\t\t\t\t} else if ( converters[ conv2 ] !== true ) {\n\t\t\t\t\t\t\t\t\tcurrent = tmp[ 0 ];\n\t\t\t\t\t\t\t\t\tdataTypes.unshift( tmp[ 1 ] );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Apply converter (if not an equivalence)\n\t\t\t\tif ( conv !== true ) {\n\n\t\t\t\t\t// Unless errors are allowed to bubble, catch and return them\n\t\t\t\t\tif ( conv && s.throws ) {\n\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tstate: \"parsererror\",\n\t\t\t\t\t\t\t\terror: conv ? e : \"No conversion from \" + prev + \" to \" + current\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { state: \"success\", data: response };\n}\n\njQuery.extend( {\n\n\t// Counter for holding the number of active queries\n\tactive: 0,\n\n\t// Last-Modified header cache for next request\n\tlastModified: {},\n\tetag: {},\n\n\tajaxSettings: {\n\t\turl: location.href,\n\t\ttype: \"GET\",\n\t\tisLocal: rlocalProtocol.test( location.protocol ),\n\t\tglobal: true,\n\t\tprocessData: true,\n\t\tasync: true,\n\t\tcontentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\n\t\t/*\n\t\ttimeout: 0,\n\t\tdata: null,\n\t\tdataType: null,\n\t\tusername: null,\n\t\tpassword: null,\n\t\tcache: null,\n\t\tthrows: false,\n\t\ttraditional: false,\n\t\theaders: {},\n\t\t*/\n\n\t\taccepts: {\n\t\t\t\"*\": allTypes,\n\t\t\ttext: \"text/plain\",\n\t\t\thtml: \"text/html\",\n\t\t\txml: \"application/xml, text/xml\",\n\t\t\tjson: \"application/json, text/javascript\"\n\t\t},\n\n\t\tcontents: {\n\t\t\txml: /\\bxml\\b/,\n\t\t\thtml: /\\bhtml/,\n\t\t\tjson: /\\bjson\\b/\n\t\t},\n\n\t\tresponseFields: {\n\t\t\txml: \"responseXML\",\n\t\t\ttext: \"responseText\",\n\t\t\tjson: \"responseJSON\"\n\t\t},\n\n\t\t// Data converters\n\t\t// Keys separate source (or catchall \"*\") and destination types with a single space\n\t\tconverters: {\n\n\t\t\t// Convert anything to text\n\t\t\t\"* text\": String,\n\n\t\t\t// Text to html (true = no transformation)\n\t\t\t\"text html\": true,\n\n\t\t\t// Evaluate text as a json expression\n\t\t\t\"text json\": jQuery.parseJSON,\n\n\t\t\t// Parse text as xml\n\t\t\t\"text xml\": jQuery.parseXML\n\t\t},\n\n\t\t// For options that shouldn't be deep extended:\n\t\t// you can add your own custom options here if\n\t\t// and when you create one that shouldn't be\n\t\t// deep extended (see ajaxExtend)\n\t\tflatOptions: {\n\t\t\turl: true,\n\t\t\tcontext: true\n\t\t}\n\t},\n\n\t// Creates a full fledged settings object into target\n\t// with both ajaxSettings and settings fields.\n\t// If target is omitted, writes into ajaxSettings.\n\tajaxSetup: function( target, settings ) {\n\t\treturn settings ?\n\n\t\t\t// Building a settings object\n\t\t\tajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :\n\n\t\t\t// Extending ajaxSettings\n\t\t\tajaxExtend( jQuery.ajaxSettings, target );\n\t},\n\n\tajaxPrefilter: addToPrefiltersOrTransports( prefilters ),\n\tajaxTransport: addToPrefiltersOrTransports( transports ),\n\n\t// Main method\n\tajax: function( url, options ) {\n\n\t\t// If url is an object, simulate pre-1.5 signature\n\t\tif ( typeof url === \"object\" ) {\n\t\t\toptions = url;\n\t\t\turl = undefined;\n\t\t}\n\n\t\t// Force options to be an object\n\t\toptions = options || {};\n\n\t\tvar transport,\n\n\t\t\t// URL without anti-cache param\n\t\t\tcacheURL,\n\n\t\t\t// Response headers\n\t\t\tresponseHeadersString,\n\t\t\tresponseHeaders,\n\n\t\t\t// timeout handle\n\t\t\ttimeoutTimer,\n\n\t\t\t// Url cleanup var\n\t\t\turlAnchor,\n\n\t\t\t// To know if global events are to be dispatched\n\t\t\tfireGlobals,\n\n\t\t\t// Loop variable\n\t\t\ti,\n\n\t\t\t// Create the final options object\n\t\t\ts = jQuery.ajaxSetup( {}, options ),\n\n\t\t\t// Callbacks context\n\t\t\tcallbackContext = s.context || s,\n\n\t\t\t// Context for global events is callbackContext if it is a DOM node or jQuery collection\n\t\t\tglobalEventContext = s.context &&\n\t\t\t\t( callbackContext.nodeType || callbackContext.jquery ) ?\n\t\t\t\t\tjQuery( callbackContext ) :\n\t\t\t\t\tjQuery.event,\n\n\t\t\t// Deferreds\n\t\t\tdeferred = jQuery.Deferred(),\n\t\t\tcompleteDeferred = jQuery.Callbacks( \"once memory\" ),\n\n\t\t\t// Status-dependent callbacks\n\t\t\tstatusCode = s.statusCode || {},\n\n\t\t\t// Headers (they are sent all at once)\n\t\t\trequestHeaders = {},\n\t\t\trequestHeadersNames = {},\n\n\t\t\t// The jqXHR state\n\t\t\tstate = 0,\n\n\t\t\t// Default abort message\n\t\t\tstrAbort = \"canceled\",\n\n\t\t\t// Fake xhr\n\t\t\tjqXHR = {\n\t\t\t\treadyState: 0,\n\n\t\t\t\t// Builds headers hashtable if needed\n\t\t\t\tgetResponseHeader: function( key ) {\n\t\t\t\t\tvar match;\n\t\t\t\t\tif ( state === 2 ) {\n\t\t\t\t\t\tif ( !responseHeaders ) {\n\t\t\t\t\t\t\tresponseHeaders = {};\n\t\t\t\t\t\t\twhile ( ( match = rheaders.exec( responseHeadersString ) ) ) {\n\t\t\t\t\t\t\t\tresponseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmatch = responseHeaders[ key.toLowerCase() ];\n\t\t\t\t\t}\n\t\t\t\t\treturn match == null ? null : match;\n\t\t\t\t},\n\n\t\t\t\t// Raw string\n\t\t\t\tgetAllResponseHeaders: function() {\n\t\t\t\t\treturn state === 2 ? responseHeadersString : null;\n\t\t\t\t},\n\n\t\t\t\t// Caches the header\n\t\t\t\tsetRequestHeader: function( name, value ) {\n\t\t\t\t\tvar lname = name.toLowerCase();\n\t\t\t\t\tif ( !state ) {\n\t\t\t\t\t\tname = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;\n\t\t\t\t\t\trequestHeaders[ name ] = value;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Overrides response content-type header\n\t\t\t\toverrideMimeType: function( type ) {\n\t\t\t\t\tif ( !state ) {\n\t\t\t\t\t\ts.mimeType = type;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Status-dependent callbacks\n\t\t\t\tstatusCode: function( map ) {\n\t\t\t\t\tvar code;\n\t\t\t\t\tif ( map ) {\n\t\t\t\t\t\tif ( state < 2 ) {\n\t\t\t\t\t\t\tfor ( code in map ) {\n\n\t\t\t\t\t\t\t\t// Lazy-add the new callback in a way that preserves old ones\n\t\t\t\t\t\t\t\tstatusCode[ code ] = [ statusCode[ code ], map[ code ] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Execute the appropriate callbacks\n\t\t\t\t\t\t\tjqXHR.always( map[ jqXHR.status ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Cancel the request\n\t\t\t\tabort: function( statusText ) {\n\t\t\t\t\tvar finalText = statusText || strAbort;\n\t\t\t\t\tif ( transport ) {\n\t\t\t\t\t\ttransport.abort( finalText );\n\t\t\t\t\t}\n\t\t\t\t\tdone( 0, finalText );\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t};\n\n\t\t// Attach deferreds\n\t\tdeferred.promise( jqXHR ).complete = completeDeferred.add;\n\t\tjqXHR.success = jqXHR.done;\n\t\tjqXHR.error = jqXHR.fail;\n\n\t\t// Remove hash character (#7531: and string promotion)\n\t\t// Add protocol if not provided (prefilters might expect it)\n\t\t// Handle falsy url in the settings object (#10093: consistency with old signature)\n\t\t// We also use the url parameter if available\n\t\ts.url = ( ( url || s.url || location.href ) + \"\" ).replace( rhash, \"\" )\n\t\t\t.replace( rprotocol, location.protocol + \"//\" );\n\n\t\t// Alias method option to type as per ticket #12004\n\t\ts.type = options.method || options.type || s.method || s.type;\n\n\t\t// Extract dataTypes list\n\t\ts.dataTypes = jQuery.trim( s.dataType || \"*\" ).toLowerCase().match( rnotwhite ) || [ \"\" ];\n\n\t\t// A cross-domain request is in order when the origin doesn't match the current origin.\n\t\tif ( s.crossDomain == null ) {\n\t\t\turlAnchor = document.createElement( \"a\" );\n\n\t\t\t// Support: IE8-11+\n\t\t\t// IE throws exception if url is malformed, e.g. http://example.com:80x/\n\t\t\ttry {\n\t\t\t\turlAnchor.href = s.url;\n\n\t\t\t\t// Support: IE8-11+\n\t\t\t\t// Anchor's host property isn't correctly set when s.url is relative\n\t\t\t\turlAnchor.href = urlAnchor.href;\n\t\t\t\ts.crossDomain = originAnchor.protocol + \"//\" + originAnchor.host !==\n\t\t\t\t\turlAnchor.protocol + \"//\" + urlAnchor.host;\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// If there is an error parsing the URL, assume it is crossDomain,\n\t\t\t\t// it can be rejected by the transport if it is invalid\n\t\t\t\ts.crossDomain = true;\n\t\t\t}\n\t\t}\n\n\t\t// Convert data if not already a string\n\t\tif ( s.data && s.processData && typeof s.data !== \"string\" ) {\n\t\t\ts.data = jQuery.param( s.data, s.traditional );\n\t\t}\n\n\t\t// Apply prefilters\n\t\tinspectPrefiltersOrTransports( prefilters, s, options, jqXHR );\n\n\t\t// If request was aborted inside a prefilter, stop there\n\t\tif ( state === 2 ) {\n\t\t\treturn jqXHR;\n\t\t}\n\n\t\t// We can fire global events as of now if asked to\n\t\t// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)\n\t\tfireGlobals = jQuery.event && s.global;\n\n\t\t// Watch for a new set of requests\n\t\tif ( fireGlobals && jQuery.active++ === 0 ) {\n\t\t\tjQuery.event.trigger( \"ajaxStart\" );\n\t\t}\n\n\t\t// Uppercase the type\n\t\ts.type = s.type.toUpperCase();\n\n\t\t// Determine if request has content\n\t\ts.hasContent = !rnoContent.test( s.type );\n\n\t\t// Save the URL in case we're toying with the If-Modified-Since\n\t\t// and/or If-None-Match header later on\n\t\tcacheURL = s.url;\n\n\t\t// More options handling for requests with no content\n\t\tif ( !s.hasContent ) {\n\n\t\t\t// If data is available, append data to url\n\t\t\tif ( s.data ) {\n\t\t\t\tcacheURL = ( s.url += ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + s.data );\n\n\t\t\t\t// #9682: remove data so that it's not used in an eventual retry\n\t\t\t\tdelete s.data;\n\t\t\t}\n\n\t\t\t// Add anti-cache in url if needed\n\t\t\tif ( s.cache === false ) {\n\t\t\t\ts.url = rts.test( cacheURL ) ?\n\n\t\t\t\t\t// If there is already a '_' parameter, set its value\n\t\t\t\t\tcacheURL.replace( rts, \"$1_=\" + nonce++ ) :\n\n\t\t\t\t\t// Otherwise add one to the end\n\t\t\t\t\tcacheURL + ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + \"_=\" + nonce++;\n\t\t\t}\n\t\t}\n\n\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\tif ( s.ifModified ) {\n\t\t\tif ( jQuery.lastModified[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-Modified-Since\", jQuery.lastModified[ cacheURL ] );\n\t\t\t}\n\t\t\tif ( jQuery.etag[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-None-Match\", jQuery.etag[ cacheURL ] );\n\t\t\t}\n\t\t}\n\n\t\t// Set the correct header, if data is being sent\n\t\tif ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {\n\t\t\tjqXHR.setRequestHeader( \"Content-Type\", s.contentType );\n\t\t}\n\n\t\t// Set the Accepts header for the server, depending on the dataType\n\t\tjqXHR.setRequestHeader(\n\t\t\t\"Accept\",\n\t\t\ts.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?\n\t\t\t\ts.accepts[ s.dataTypes[ 0 ] ] +\n\t\t\t\t\t( s.dataTypes[ 0 ] !== \"*\" ? \", \" + allTypes + \"; q=0.01\" : \"\" ) :\n\t\t\t\ts.accepts[ \"*\" ]\n\t\t);\n\n\t\t// Check for headers option\n\t\tfor ( i in s.headers ) {\n\t\t\tjqXHR.setRequestHeader( i, s.headers[ i ] );\n\t\t}\n\n\t\t// Allow custom headers/mimetypes and early abort\n\t\tif ( s.beforeSend &&\n\t\t\t( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {\n\n\t\t\t// Abort if not done already and return\n\t\t\treturn jqXHR.abort();\n\t\t}\n\n\t\t// Aborting is no longer a cancellation\n\t\tstrAbort = \"abort\";\n\n\t\t// Install callbacks on deferreds\n\t\tfor ( i in { success: 1, error: 1, complete: 1 } ) {\n\t\t\tjqXHR[ i ]( s[ i ] );\n\t\t}\n\n\t\t// Get transport\n\t\ttransport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );\n\n\t\t// If no transport, we auto-abort\n\t\tif ( !transport ) {\n\t\t\tdone( -1, \"No Transport\" );\n\t\t} else {\n\t\t\tjqXHR.readyState = 1;\n\n\t\t\t// Send global event\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxSend\", [ jqXHR, s ] );\n\t\t\t}\n\n\t\t\t// If request was aborted inside ajaxSend, stop there\n\t\t\tif ( state === 2 ) {\n\t\t\t\treturn jqXHR;\n\t\t\t}\n\n\t\t\t// Timeout\n\t\t\tif ( s.async && s.timeout > 0 ) {\n\t\t\t\ttimeoutTimer = window.setTimeout( function() {\n\t\t\t\t\tjqXHR.abort( \"timeout\" );\n\t\t\t\t}, s.timeout );\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tstate = 1;\n\t\t\t\ttransport.send( requestHeaders, done );\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// Propagate exception as error if not done\n\t\t\t\tif ( state < 2 ) {\n\t\t\t\t\tdone( -1, e );\n\n\t\t\t\t// Simply rethrow otherwise\n\t\t\t\t} else {\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Callback for when everything is done\n\t\tfunction done( status, nativeStatusText, responses, headers ) {\n\t\t\tvar isSuccess, success, error, response, modified,\n\t\t\t\tstatusText = nativeStatusText;\n\n\t\t\t// Called once\n\t\t\tif ( state === 2 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// State is \"done\" now\n\t\t\tstate = 2;\n\n\t\t\t// Clear timeout if it exists\n\t\t\tif ( timeoutTimer ) {\n\t\t\t\twindow.clearTimeout( timeoutTimer );\n\t\t\t}\n\n\t\t\t// Dereference transport for early garbage collection\n\t\t\t// (no matter how long the jqXHR object will be used)\n\t\t\ttransport = undefined;\n\n\t\t\t// Cache response headers\n\t\t\tresponseHeadersString = headers || \"\";\n\n\t\t\t// Set readyState\n\t\t\tjqXHR.readyState = status > 0 ? 4 : 0;\n\n\t\t\t// Determine if successful\n\t\t\tisSuccess = status >= 200 && status < 300 || status === 304;\n\n\t\t\t// Get response data\n\t\t\tif ( responses ) {\n\t\t\t\tresponse = ajaxHandleResponses( s, jqXHR, responses );\n\t\t\t}\n\n\t\t\t// Convert no matter what (that way responseXXX fields are always set)\n\t\t\tresponse = ajaxConvert( s, response, jqXHR, isSuccess );\n\n\t\t\t// If successful, handle type chaining\n\t\t\tif ( isSuccess ) {\n\n\t\t\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\t\t\tif ( s.ifModified ) {\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"Last-Modified\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.lastModified[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"etag\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.etag[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if no content\n\t\t\t\tif ( status === 204 || s.type === \"HEAD\" ) {\n\t\t\t\t\tstatusText = \"nocontent\";\n\n\t\t\t\t// if not modified\n\t\t\t\t} else if ( status === 304 ) {\n\t\t\t\t\tstatusText = \"notmodified\";\n\n\t\t\t\t// If we have data, let's convert it\n\t\t\t\t} else {\n\t\t\t\t\tstatusText = response.state;\n\t\t\t\t\tsuccess = response.data;\n\t\t\t\t\terror = response.error;\n\t\t\t\t\tisSuccess = !error;\n\t\t\t\t}\n\t\t\t} else {\n\n\t\t\t\t// Extract error from statusText and normalize for non-aborts\n\t\t\t\terror = statusText;\n\t\t\t\tif ( status || !statusText ) {\n\t\t\t\t\tstatusText = \"error\";\n\t\t\t\t\tif ( status < 0 ) {\n\t\t\t\t\t\tstatus = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set data for the fake xhr object\n\t\t\tjqXHR.status = status;\n\t\t\tjqXHR.statusText = ( nativeStatusText || statusText ) + \"\";\n\n\t\t\t// Success/Error\n\t\t\tif ( isSuccess ) {\n\t\t\t\tdeferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );\n\t\t\t} else {\n\t\t\t\tdeferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );\n\t\t\t}\n\n\t\t\t// Status-dependent callbacks\n\t\t\tjqXHR.statusCode( statusCode );\n\t\t\tstatusCode = undefined;\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( isSuccess ? \"ajaxSuccess\" : \"ajaxError\",\n\t\t\t\t\t[ jqXHR, s, isSuccess ? success : error ] );\n\t\t\t}\n\n\t\t\t// Complete\n\t\t\tcompleteDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxComplete\", [ jqXHR, s ] );\n\n\t\t\t\t// Handle the global AJAX counter\n\t\t\t\tif ( !( --jQuery.active ) ) {\n\t\t\t\t\tjQuery.event.trigger( \"ajaxStop\" );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jqXHR;\n\t},\n\n\tgetJSON: function( url, data, callback ) {\n\t\treturn jQuery.get( url, data, callback, \"json\" );\n\t},\n\n\tgetScript: function( url, callback ) {\n\t\treturn jQuery.get( url, undefined, callback, \"script\" );\n\t}\n} );\n\njQuery.each( [ \"get\", \"post\" ], function( i, method ) {\n\tjQuery[ method ] = function( url, data, callback, type ) {\n\n\t\t// Shift arguments if data argument was omitted\n\t\tif ( jQuery.isFunction( data ) ) {\n\t\t\ttype = type || callback;\n\t\t\tcallback = data;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\t// The url can be an options object (which then must have .url)\n\t\treturn jQuery.ajax( jQuery.extend( {\n\t\t\turl: url,\n\t\t\ttype: method,\n\t\t\tdataType: type,\n\t\t\tdata: data,\n\t\t\tsuccess: callback\n\t\t}, jQuery.isPlainObject( url ) && url ) );\n\t};\n} );\n\n\njQuery._evalUrl = function( url ) {\n\treturn jQuery.ajax( {\n\t\turl: url,\n\n\t\t// Make this explicit, since user can override this through ajaxSetup (#11264)\n\t\ttype: \"GET\",\n\t\tdataType: \"script\",\n\t\tasync: false,\n\t\tglobal: false,\n\t\t\"throws\": true\n\t} );\n};\n\n\njQuery.fn.extend( {\n\twrapAll: function( html ) {\n\t\tvar wrap;\n\n\t\tif ( jQuery.isFunction( html ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).wrapAll( html.call( this, i ) );\n\t\t\t} );\n\t\t}\n\n\t\tif ( this[ 0 ] ) {\n\n\t\t\t// The elements to wrap the target around\n\t\t\twrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );\n\n\t\t\tif ( this[ 0 ].parentNode ) {\n\t\t\t\twrap.insertBefore( this[ 0 ] );\n\t\t\t}\n\n\t\t\twrap.map( function() {\n\t\t\t\tvar elem = this;\n\n\t\t\t\twhile ( elem.firstElementChild ) {\n\t\t\t\t\telem = elem.firstElementChild;\n\t\t\t\t}\n\n\t\t\t\treturn elem;\n\t\t\t} ).append( this );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\twrapInner: function( html ) {\n\t\tif ( jQuery.isFunction( html ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).wrapInner( html.call( this, i ) );\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar self = jQuery( this ),\n\t\t\t\tcontents = self.contents();\n\n\t\t\tif ( contents.length ) {\n\t\t\t\tcontents.wrapAll( html );\n\n\t\t\t} else {\n\t\t\t\tself.append( html );\n\t\t\t}\n\t\t} );\n\t},\n\n\twrap: function( html ) {\n\t\tvar isFunction = jQuery.isFunction( html );\n\n\t\treturn this.each( function( i ) {\n\t\t\tjQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html );\n\t\t} );\n\t},\n\n\tunwrap: function() {\n\t\treturn this.parent().each( function() {\n\t\t\tif ( !jQuery.nodeName( this, \"body\" ) ) {\n\t\t\t\tjQuery( this ).replaceWith( this.childNodes );\n\t\t\t}\n\t\t} ).end();\n\t}\n} );\n\n\njQuery.expr.filters.hidden = function( elem ) {\n\treturn !jQuery.expr.filters.visible( elem );\n};\njQuery.expr.filters.visible = function( elem ) {\n\n\t// Support: Opera <= 12.12\n\t// Opera reports offsetWidths and offsetHeights less than zero on some elements\n\t// Use OR instead of AND as the element is not visible if either is true\n\t// See tickets #10406 and #13132\n\treturn elem.offsetWidth > 0 || elem.offsetHeight > 0 || elem.getClientRects().length > 0;\n};\n\n\n\n\nvar r20 = /%20/g,\n\trbracket = /\\[\\]$/,\n\trCRLF = /\\r?\\n/g,\n\trsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,\n\trsubmittable = /^(?:input|select|textarea|keygen)/i;\n\nfunction buildParams( prefix, obj, traditional, add ) {\n\tvar name;\n\n\tif ( jQuery.isArray( obj ) ) {\n\n\t\t// Serialize array item.\n\t\tjQuery.each( obj, function( i, v ) {\n\t\t\tif ( traditional || rbracket.test( prefix ) ) {\n\n\t\t\t\t// Treat each array item as a scalar.\n\t\t\t\tadd( prefix, v );\n\n\t\t\t} else {\n\n\t\t\t\t// Item is non-scalar (array or object), encode its numeric index.\n\t\t\t\tbuildParams(\n\t\t\t\t\tprefix + \"[\" + ( typeof v === \"object\" && v != null ? i : \"\" ) + \"]\",\n\t\t\t\t\tv,\n\t\t\t\t\ttraditional,\n\t\t\t\t\tadd\n\t\t\t\t);\n\t\t\t}\n\t\t} );\n\n\t} else if ( !traditional && jQuery.type( obj ) === \"object\" ) {\n\n\t\t// Serialize object item.\n\t\tfor ( name in obj ) {\n\t\t\tbuildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n\t\t}\n\n\t} else {\n\n\t\t// Serialize scalar item.\n\t\tadd( prefix, obj );\n\t}\n}\n\n// Serialize an array of form elements or a set of\n// key/values into a query string\njQuery.param = function( a, traditional ) {\n\tvar prefix,\n\t\ts = [],\n\t\tadd = function( key, value ) {\n\n\t\t\t// If value is a function, invoke it and return its value\n\t\t\tvalue = jQuery.isFunction( value ) ? value() : ( value == null ? \"\" : value );\n\t\t\ts[ s.length ] = encodeURIComponent( key ) + \"=\" + encodeURIComponent( value );\n\t\t};\n\n\t// Set traditional to true for jQuery <= 1.3.2 behavior.\n\tif ( traditional === undefined ) {\n\t\ttraditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;\n\t}\n\n\t// If an array was passed in, assume that it is an array of form elements.\n\tif ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n\n\t\t// Serialize the form elements\n\t\tjQuery.each( a, function() {\n\t\t\tadd( this.name, this.value );\n\t\t} );\n\n\t} else {\n\n\t\t// If traditional, encode the \"old\" way (the way 1.3.2 or older\n\t\t// did it), otherwise encode params recursively.\n\t\tfor ( prefix in a ) {\n\t\t\tbuildParams( prefix, a[ prefix ], traditional, add );\n\t\t}\n\t}\n\n\t// Return the resulting serialization\n\treturn s.join( \"&\" ).replace( r20, \"+\" );\n};\n\njQuery.fn.extend( {\n\tserialize: function() {\n\t\treturn jQuery.param( this.serializeArray() );\n\t},\n\tserializeArray: function() {\n\t\treturn this.map( function() {\n\n\t\t\t// Can add propHook for \"elements\" to filter or add form elements\n\t\t\tvar elements = jQuery.prop( this, \"elements\" );\n\t\t\treturn elements ? jQuery.makeArray( elements ) : this;\n\t\t} )\n\t\t.filter( function() {\n\t\t\tvar type = this.type;\n\n\t\t\t// Use .is( \":disabled\" ) so that fieldset[disabled] works\n\t\t\treturn this.name && !jQuery( this ).is( \":disabled\" ) &&\n\t\t\t\trsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&\n\t\t\t\t( this.checked || !rcheckableType.test( type ) );\n\t\t} )\n\t\t.map( function( i, elem ) {\n\t\t\tvar val = jQuery( this ).val();\n\n\t\t\treturn val == null ?\n\t\t\t\tnull :\n\t\t\t\tjQuery.isArray( val ) ?\n\t\t\t\t\tjQuery.map( val, function( val ) {\n\t\t\t\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t\t\t\t} ) :\n\t\t\t\t\t{ name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t} ).get();\n\t}\n} );\n\n\njQuery.ajaxSettings.xhr = function() {\n\ttry {\n\t\treturn new window.XMLHttpRequest();\n\t} catch ( e ) {}\n};\n\nvar xhrSuccessStatus = {\n\n\t\t// File protocol always yields status code 0, assume 200\n\t\t0: 200,\n\n\t\t// Support: IE9\n\t\t// #1450: sometimes IE returns 1223 when it should be 204\n\t\t1223: 204\n\t},\n\txhrSupported = jQuery.ajaxSettings.xhr();\n\nsupport.cors = !!xhrSupported && ( \"withCredentials\" in xhrSupported );\nsupport.ajax = xhrSupported = !!xhrSupported;\n\njQuery.ajaxTransport( function( options ) {\n\tvar callback, errorCallback;\n\n\t// Cross domain only allowed if supported through XMLHttpRequest\n\tif ( support.cors || xhrSupported && !options.crossDomain ) {\n\t\treturn {\n\t\t\tsend: function( headers, complete ) {\n\t\t\t\tvar i,\n\t\t\t\t\txhr = options.xhr();\n\n\t\t\t\txhr.open(\n\t\t\t\t\toptions.type,\n\t\t\t\t\toptions.url,\n\t\t\t\t\toptions.async,\n\t\t\t\t\toptions.username,\n\t\t\t\t\toptions.password\n\t\t\t\t);\n\n\t\t\t\t// Apply custom fields if provided\n\t\t\t\tif ( options.xhrFields ) {\n\t\t\t\t\tfor ( i in options.xhrFields ) {\n\t\t\t\t\t\txhr[ i ] = options.xhrFields[ i ];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Override mime type if needed\n\t\t\t\tif ( options.mimeType && xhr.overrideMimeType ) {\n\t\t\t\t\txhr.overrideMimeType( options.mimeType );\n\t\t\t\t}\n\n\t\t\t\t// X-Requested-With header\n\t\t\t\t// For cross-domain requests, seeing as conditions for a preflight are\n\t\t\t\t// akin to a jigsaw puzzle, we simply never set it to be sure.\n\t\t\t\t// (it can always be set on a per-request basis or even using ajaxSetup)\n\t\t\t\t// For same-domain requests, won't change header if already provided.\n\t\t\t\tif ( !options.crossDomain && !headers[ \"X-Requested-With\" ] ) {\n\t\t\t\t\theaders[ \"X-Requested-With\" ] = \"XMLHttpRequest\";\n\t\t\t\t}\n\n\t\t\t\t// Set headers\n\t\t\t\tfor ( i in headers ) {\n\t\t\t\t\txhr.setRequestHeader( i, headers[ i ] );\n\t\t\t\t}\n\n\t\t\t\t// Callback\n\t\t\t\tcallback = function( type ) {\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\tcallback = errorCallback = xhr.onload =\n\t\t\t\t\t\t\t\txhr.onerror = xhr.onabort = xhr.onreadystatechange = null;\n\n\t\t\t\t\t\t\tif ( type === \"abort\" ) {\n\t\t\t\t\t\t\t\txhr.abort();\n\t\t\t\t\t\t\t} else if ( type === \"error\" ) {\n\n\t\t\t\t\t\t\t\t// Support: IE9\n\t\t\t\t\t\t\t\t// On a manual native abort, IE9 throws\n\t\t\t\t\t\t\t\t// errors on any property access that is not readyState\n\t\t\t\t\t\t\t\tif ( typeof xhr.status !== \"number\" ) {\n\t\t\t\t\t\t\t\t\tcomplete( 0, \"error\" );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tcomplete(\n\n\t\t\t\t\t\t\t\t\t\t// File: protocol always yields status 0; see #8605, #14207\n\t\t\t\t\t\t\t\t\t\txhr.status,\n\t\t\t\t\t\t\t\t\t\txhr.statusText\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcomplete(\n\t\t\t\t\t\t\t\t\txhrSuccessStatus[ xhr.status ] || xhr.status,\n\t\t\t\t\t\t\t\t\txhr.statusText,\n\n\t\t\t\t\t\t\t\t\t// Support: IE9 only\n\t\t\t\t\t\t\t\t\t// IE9 has no XHR2 but throws on binary (trac-11426)\n\t\t\t\t\t\t\t\t\t// For XHR2 non-text, let the caller handle it (gh-2498)\n\t\t\t\t\t\t\t\t\t( xhr.responseType || \"text\" ) !== \"text\"  ||\n\t\t\t\t\t\t\t\t\ttypeof xhr.responseText !== \"string\" ?\n\t\t\t\t\t\t\t\t\t\t{ binary: xhr.response } :\n\t\t\t\t\t\t\t\t\t\t{ text: xhr.responseText },\n\t\t\t\t\t\t\t\t\txhr.getAllResponseHeaders()\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t};\n\n\t\t\t\t// Listen to events\n\t\t\t\txhr.onload = callback();\n\t\t\t\terrorCallback = xhr.onerror = callback( \"error\" );\n\n\t\t\t\t// Support: IE9\n\t\t\t\t// Use onreadystatechange to replace onabort\n\t\t\t\t// to handle uncaught aborts\n\t\t\t\tif ( xhr.onabort !== undefined ) {\n\t\t\t\t\txhr.onabort = errorCallback;\n\t\t\t\t} else {\n\t\t\t\t\txhr.onreadystatechange = function() {\n\n\t\t\t\t\t\t// Check readyState before timeout as it changes\n\t\t\t\t\t\tif ( xhr.readyState === 4 ) {\n\n\t\t\t\t\t\t\t// Allow onerror to be called first,\n\t\t\t\t\t\t\t// but that will not handle a native abort\n\t\t\t\t\t\t\t// Also, save errorCallback to a variable\n\t\t\t\t\t\t\t// as xhr.onerror cannot be accessed\n\t\t\t\t\t\t\twindow.setTimeout( function() {\n\t\t\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\t\t\terrorCallback();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Create the abort callback\n\t\t\t\tcallback = callback( \"abort\" );\n\n\t\t\t\ttry {\n\n\t\t\t\t\t// Do send the request (this may raise an exception)\n\t\t\t\t\txhr.send( options.hasContent && options.data || null );\n\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t// #14683: Only rethrow if this hasn't been notified as an error yet\n\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n} );\n\n\n\n\n// Install script dataType\njQuery.ajaxSetup( {\n\taccepts: {\n\t\tscript: \"text/javascript, application/javascript, \" +\n\t\t\t\"application/ecmascript, application/x-ecmascript\"\n\t},\n\tcontents: {\n\t\tscript: /\\b(?:java|ecma)script\\b/\n\t},\n\tconverters: {\n\t\t\"text script\": function( text ) {\n\t\t\tjQuery.globalEval( text );\n\t\t\treturn text;\n\t\t}\n\t}\n} );\n\n// Handle cache's special case and crossDomain\njQuery.ajaxPrefilter( \"script\", function( s ) {\n\tif ( s.cache === undefined ) {\n\t\ts.cache = false;\n\t}\n\tif ( s.crossDomain ) {\n\t\ts.type = \"GET\";\n\t}\n} );\n\n// Bind script tag hack transport\njQuery.ajaxTransport( \"script\", function( s ) {\n\n\t// This transport only deals with cross domain requests\n\tif ( s.crossDomain ) {\n\t\tvar script, callback;\n\t\treturn {\n\t\t\tsend: function( _, complete ) {\n\t\t\t\tscript = jQuery( \"<script>\" ).prop( {\n\t\t\t\t\tcharset: s.scriptCharset,\n\t\t\t\t\tsrc: s.url\n\t\t\t\t} ).on(\n\t\t\t\t\t\"load error\",\n\t\t\t\t\tcallback = function( evt ) {\n\t\t\t\t\t\tscript.remove();\n\t\t\t\t\t\tcallback = null;\n\t\t\t\t\t\tif ( evt ) {\n\t\t\t\t\t\t\tcomplete( evt.type === \"error\" ? 404 : 200, evt.type );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t);\n\n\t\t\t\t// Use native DOM manipulation to avoid our domManip AJAX trickery\n\t\t\t\tdocument.head.appendChild( script[ 0 ] );\n\t\t\t},\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n} );\n\n\n\n\nvar oldCallbacks = [],\n\trjsonp = /(=)\\?(?=&|$)|\\?\\?/;\n\n// Default jsonp settings\njQuery.ajaxSetup( {\n\tjsonp: \"callback\",\n\tjsonpCallback: function() {\n\t\tvar callback = oldCallbacks.pop() || ( jQuery.expando + \"_\" + ( nonce++ ) );\n\t\tthis[ callback ] = true;\n\t\treturn callback;\n\t}\n} );\n\n// Detect, normalize options and install callbacks for jsonp requests\njQuery.ajaxPrefilter( \"json jsonp\", function( s, originalSettings, jqXHR ) {\n\n\tvar callbackName, overwritten, responseContainer,\n\t\tjsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?\n\t\t\t\"url\" :\n\t\t\ttypeof s.data === \"string\" &&\n\t\t\t\t( s.contentType || \"\" )\n\t\t\t\t\t.indexOf( \"application/x-www-form-urlencoded\" ) === 0 &&\n\t\t\t\trjsonp.test( s.data ) && \"data\"\n\t\t);\n\n\t// Handle iff the expected data type is \"jsonp\" or we have a parameter to set\n\tif ( jsonProp || s.dataTypes[ 0 ] === \"jsonp\" ) {\n\n\t\t// Get callback name, remembering preexisting value associated with it\n\t\tcallbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?\n\t\t\ts.jsonpCallback() :\n\t\t\ts.jsonpCallback;\n\n\t\t// Insert callback into url or form data\n\t\tif ( jsonProp ) {\n\t\t\ts[ jsonProp ] = s[ jsonProp ].replace( rjsonp, \"$1\" + callbackName );\n\t\t} else if ( s.jsonp !== false ) {\n\t\t\ts.url += ( rquery.test( s.url ) ? \"&\" : \"?\" ) + s.jsonp + \"=\" + callbackName;\n\t\t}\n\n\t\t// Use data converter to retrieve json after script execution\n\t\ts.converters[ \"script json\" ] = function() {\n\t\t\tif ( !responseContainer ) {\n\t\t\t\tjQuery.error( callbackName + \" was not called\" );\n\t\t\t}\n\t\t\treturn responseContainer[ 0 ];\n\t\t};\n\n\t\t// Force json dataType\n\t\ts.dataTypes[ 0 ] = \"json\";\n\n\t\t// Install callback\n\t\toverwritten = window[ callbackName ];\n\t\twindow[ callbackName ] = function() {\n\t\t\tresponseContainer = arguments;\n\t\t};\n\n\t\t// Clean-up function (fires after converters)\n\t\tjqXHR.always( function() {\n\n\t\t\t// If previous value didn't exist - remove it\n\t\t\tif ( overwritten === undefined ) {\n\t\t\t\tjQuery( window ).removeProp( callbackName );\n\n\t\t\t// Otherwise restore preexisting value\n\t\t\t} else {\n\t\t\t\twindow[ callbackName ] = overwritten;\n\t\t\t}\n\n\t\t\t// Save back as free\n\t\t\tif ( s[ callbackName ] ) {\n\n\t\t\t\t// Make sure that re-using the options doesn't screw things around\n\t\t\t\ts.jsonpCallback = originalSettings.jsonpCallback;\n\n\t\t\t\t// Save the callback name for future use\n\t\t\t\toldCallbacks.push( callbackName );\n\t\t\t}\n\n\t\t\t// Call if it was a function and we have a response\n\t\t\tif ( responseContainer && jQuery.isFunction( overwritten ) ) {\n\t\t\t\toverwritten( responseContainer[ 0 ] );\n\t\t\t}\n\n\t\t\tresponseContainer = overwritten = undefined;\n\t\t} );\n\n\t\t// Delegate to script\n\t\treturn \"script\";\n\t}\n} );\n\n\n\n\n// Argument \"data\" should be string of html\n// context (optional): If specified, the fragment will be created in this context,\n// defaults to document\n// keepScripts (optional): If true, will include scripts passed in the html string\njQuery.parseHTML = function( data, context, keepScripts ) {\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\tif ( typeof context === \"boolean\" ) {\n\t\tkeepScripts = context;\n\t\tcontext = false;\n\t}\n\tcontext = context || document;\n\n\tvar parsed = rsingleTag.exec( data ),\n\t\tscripts = !keepScripts && [];\n\n\t// Single tag\n\tif ( parsed ) {\n\t\treturn [ context.createElement( parsed[ 1 ] ) ];\n\t}\n\n\tparsed = buildFragment( [ data ], context, scripts );\n\n\tif ( scripts && scripts.length ) {\n\t\tjQuery( scripts ).remove();\n\t}\n\n\treturn jQuery.merge( [], parsed.childNodes );\n};\n\n\n// Keep a copy of the old load method\nvar _load = jQuery.fn.load;\n\n/**\n * Load a url into a page\n */\njQuery.fn.load = function( url, params, callback ) {\n\tif ( typeof url !== \"string\" && _load ) {\n\t\treturn _load.apply( this, arguments );\n\t}\n\n\tvar selector, type, response,\n\t\tself = this,\n\t\toff = url.indexOf( \" \" );\n\n\tif ( off > -1 ) {\n\t\tselector = jQuery.trim( url.slice( off ) );\n\t\turl = url.slice( 0, off );\n\t}\n\n\t// If it's a function\n\tif ( jQuery.isFunction( params ) ) {\n\n\t\t// We assume that it's the callback\n\t\tcallback = params;\n\t\tparams = undefined;\n\n\t// Otherwise, build a param string\n\t} else if ( params && typeof params === \"object\" ) {\n\t\ttype = \"POST\";\n\t}\n\n\t// If we have elements to modify, make the request\n\tif ( self.length > 0 ) {\n\t\tjQuery.ajax( {\n\t\t\turl: url,\n\n\t\t\t// If \"type\" variable is undefined, then \"GET\" method will be used.\n\t\t\t// Make value of this field explicit since\n\t\t\t// user can override it through ajaxSetup method\n\t\t\ttype: type || \"GET\",\n\t\t\tdataType: \"html\",\n\t\t\tdata: params\n\t\t} ).done( function( responseText ) {\n\n\t\t\t// Save response for use in complete callback\n\t\t\tresponse = arguments;\n\n\t\t\tself.html( selector ?\n\n\t\t\t\t// If a selector was specified, locate the right elements in a dummy div\n\t\t\t\t// Exclude scripts to avoid IE 'Permission Denied' errors\n\t\t\t\tjQuery( \"<div>\" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :\n\n\t\t\t\t// Otherwise use the full result\n\t\t\t\tresponseText );\n\n\t\t// If the request succeeds, this function gets \"data\", \"status\", \"jqXHR\"\n\t\t// but they are ignored because response was set above.\n\t\t// If it fails, this function gets \"jqXHR\", \"status\", \"error\"\n\t\t} ).always( callback && function( jqXHR, status ) {\n\t\t\tself.each( function() {\n\t\t\t\tcallback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );\n\t\t\t} );\n\t\t} );\n\t}\n\n\treturn this;\n};\n\n\n\n\n// Attach a bunch of functions for handling common AJAX events\njQuery.each( [\n\t\"ajaxStart\",\n\t\"ajaxStop\",\n\t\"ajaxComplete\",\n\t\"ajaxError\",\n\t\"ajaxSuccess\",\n\t\"ajaxSend\"\n], function( i, type ) {\n\tjQuery.fn[ type ] = function( fn ) {\n\t\treturn this.on( type, fn );\n\t};\n} );\n\n\n\n\njQuery.expr.filters.animated = function( elem ) {\n\treturn jQuery.grep( jQuery.timers, function( fn ) {\n\t\treturn elem === fn.elem;\n\t} ).length;\n};\n\n\n\n\n/**\n * Gets a window from an element\n */\nfunction getWindow( elem ) {\n\treturn jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;\n}\n\njQuery.offset = {\n\tsetOffset: function( elem, options, i ) {\n\t\tvar curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,\n\t\t\tposition = jQuery.css( elem, \"position\" ),\n\t\t\tcurElem = jQuery( elem ),\n\t\t\tprops = {};\n\n\t\t// Set position first, in-case top/left are set even on static elem\n\t\tif ( position === \"static\" ) {\n\t\t\telem.style.position = \"relative\";\n\t\t}\n\n\t\tcurOffset = curElem.offset();\n\t\tcurCSSTop = jQuery.css( elem, \"top\" );\n\t\tcurCSSLeft = jQuery.css( elem, \"left\" );\n\t\tcalculatePosition = ( position === \"absolute\" || position === \"fixed\" ) &&\n\t\t\t( curCSSTop + curCSSLeft ).indexOf( \"auto\" ) > -1;\n\n\t\t// Need to be able to calculate position if either\n\t\t// top or left is auto and position is either absolute or fixed\n\t\tif ( calculatePosition ) {\n\t\t\tcurPosition = curElem.position();\n\t\t\tcurTop = curPosition.top;\n\t\t\tcurLeft = curPosition.left;\n\n\t\t} else {\n\t\t\tcurTop = parseFloat( curCSSTop ) || 0;\n\t\t\tcurLeft = parseFloat( curCSSLeft ) || 0;\n\t\t}\n\n\t\tif ( jQuery.isFunction( options ) ) {\n\n\t\t\t// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)\n\t\t\toptions = options.call( elem, i, jQuery.extend( {}, curOffset ) );\n\t\t}\n\n\t\tif ( options.top != null ) {\n\t\t\tprops.top = ( options.top - curOffset.top ) + curTop;\n\t\t}\n\t\tif ( options.left != null ) {\n\t\t\tprops.left = ( options.left - curOffset.left ) + curLeft;\n\t\t}\n\n\t\tif ( \"using\" in options ) {\n\t\t\toptions.using.call( elem, props );\n\n\t\t} else {\n\t\t\tcurElem.css( props );\n\t\t}\n\t}\n};\n\njQuery.fn.extend( {\n\toffset: function( options ) {\n\t\tif ( arguments.length ) {\n\t\t\treturn options === undefined ?\n\t\t\t\tthis :\n\t\t\t\tthis.each( function( i ) {\n\t\t\t\t\tjQuery.offset.setOffset( this, options, i );\n\t\t\t\t} );\n\t\t}\n\n\t\tvar docElem, win,\n\t\t\telem = this[ 0 ],\n\t\t\tbox = { top: 0, left: 0 },\n\t\t\tdoc = elem && elem.ownerDocument;\n\n\t\tif ( !doc ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdocElem = doc.documentElement;\n\n\t\t// Make sure it's not a disconnected DOM node\n\t\tif ( !jQuery.contains( docElem, elem ) ) {\n\t\t\treturn box;\n\t\t}\n\n\t\tbox = elem.getBoundingClientRect();\n\t\twin = getWindow( doc );\n\t\treturn {\n\t\t\ttop: box.top + win.pageYOffset - docElem.clientTop,\n\t\t\tleft: box.left + win.pageXOffset - docElem.clientLeft\n\t\t};\n\t},\n\n\tposition: function() {\n\t\tif ( !this[ 0 ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar offsetParent, offset,\n\t\t\telem = this[ 0 ],\n\t\t\tparentOffset = { top: 0, left: 0 };\n\n\t\t// Fixed elements are offset from window (parentOffset = {top:0, left: 0},\n\t\t// because it is its only offset parent\n\t\tif ( jQuery.css( elem, \"position\" ) === \"fixed\" ) {\n\n\t\t\t// Assume getBoundingClientRect is there when computed position is fixed\n\t\t\toffset = elem.getBoundingClientRect();\n\n\t\t} else {\n\n\t\t\t// Get *real* offsetParent\n\t\t\toffsetParent = this.offsetParent();\n\n\t\t\t// Get correct offsets\n\t\t\toffset = this.offset();\n\t\t\tif ( !jQuery.nodeName( offsetParent[ 0 ], \"html\" ) ) {\n\t\t\t\tparentOffset = offsetParent.offset();\n\t\t\t}\n\n\t\t\t// Add offsetParent borders\n\t\t\tparentOffset.top += jQuery.css( offsetParent[ 0 ], \"borderTopWidth\", true );\n\t\t\tparentOffset.left += jQuery.css( offsetParent[ 0 ], \"borderLeftWidth\", true );\n\t\t}\n\n\t\t// Subtract parent offsets and element margins\n\t\treturn {\n\t\t\ttop: offset.top - parentOffset.top - jQuery.css( elem, \"marginTop\", true ),\n\t\t\tleft: offset.left - parentOffset.left - jQuery.css( elem, \"marginLeft\", true )\n\t\t};\n\t},\n\n\t// This method will return documentElement in the following cases:\n\t// 1) For the element inside the iframe without offsetParent, this method will return\n\t//    documentElement of the parent window\n\t// 2) For the hidden or detached element\n\t// 3) For body or html element, i.e. in case of the html node - it will return itself\n\t//\n\t// but those exceptions were never presented as a real life use-cases\n\t// and might be considered as more preferable results.\n\t//\n\t// This logic, however, is not guaranteed and can change at any point in the future\n\toffsetParent: function() {\n\t\treturn this.map( function() {\n\t\t\tvar offsetParent = this.offsetParent;\n\n\t\t\twhile ( offsetParent && jQuery.css( offsetParent, \"position\" ) === \"static\" ) {\n\t\t\t\toffsetParent = offsetParent.offsetParent;\n\t\t\t}\n\n\t\t\treturn offsetParent || documentElement;\n\t\t} );\n\t}\n} );\n\n// Create scrollLeft and scrollTop methods\njQuery.each( { scrollLeft: \"pageXOffset\", scrollTop: \"pageYOffset\" }, function( method, prop ) {\n\tvar top = \"pageYOffset\" === prop;\n\n\tjQuery.fn[ method ] = function( val ) {\n\t\treturn access( this, function( elem, method, val ) {\n\t\t\tvar win = getWindow( elem );\n\n\t\t\tif ( val === undefined ) {\n\t\t\t\treturn win ? win[ prop ] : elem[ method ];\n\t\t\t}\n\n\t\t\tif ( win ) {\n\t\t\t\twin.scrollTo(\n\t\t\t\t\t!top ? val : win.pageXOffset,\n\t\t\t\t\ttop ? val : win.pageYOffset\n\t\t\t\t);\n\n\t\t\t} else {\n\t\t\t\telem[ method ] = val;\n\t\t\t}\n\t\t}, method, val, arguments.length );\n\t};\n} );\n\n// Support: Safari<7-8+, Chrome<37-44+\n// Add the top/left cssHooks using jQuery.fn.position\n// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084\n// Blink bug: https://code.google.com/p/chromium/issues/detail?id=229280\n// getComputedStyle returns percent when specified for top/left/bottom/right;\n// rather than make the css module depend on the offset module, just check for it here\njQuery.each( [ \"top\", \"left\" ], function( i, prop ) {\n\tjQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,\n\t\tfunction( elem, computed ) {\n\t\t\tif ( computed ) {\n\t\t\t\tcomputed = curCSS( elem, prop );\n\n\t\t\t\t// If curCSS returns percentage, fallback to offset\n\t\t\t\treturn rnumnonpx.test( computed ) ?\n\t\t\t\t\tjQuery( elem ).position()[ prop ] + \"px\" :\n\t\t\t\t\tcomputed;\n\t\t\t}\n\t\t}\n\t);\n} );\n\n\n// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods\njQuery.each( { Height: \"height\", Width: \"width\" }, function( name, type ) {\n\tjQuery.each( { padding: \"inner\" + name, content: type, \"\": \"outer\" + name },\n\t\tfunction( defaultExtra, funcName ) {\n\n\t\t// Margin is only for outerHeight, outerWidth\n\t\tjQuery.fn[ funcName ] = function( margin, value ) {\n\t\t\tvar chainable = arguments.length && ( defaultExtra || typeof margin !== \"boolean\" ),\n\t\t\t\textra = defaultExtra || ( margin === true || value === true ? \"margin\" : \"border\" );\n\n\t\t\treturn access( this, function( elem, type, value ) {\n\t\t\t\tvar doc;\n\n\t\t\t\tif ( jQuery.isWindow( elem ) ) {\n\n\t\t\t\t\t// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there\n\t\t\t\t\t// isn't a whole lot we can do. See pull request at this URL for discussion:\n\t\t\t\t\t// https://github.com/jquery/jquery/pull/764\n\t\t\t\t\treturn elem.document.documentElement[ \"client\" + name ];\n\t\t\t\t}\n\n\t\t\t\t// Get document width or height\n\t\t\t\tif ( elem.nodeType === 9 ) {\n\t\t\t\t\tdoc = elem.documentElement;\n\n\t\t\t\t\t// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],\n\t\t\t\t\t// whichever is greatest\n\t\t\t\t\treturn Math.max(\n\t\t\t\t\t\telem.body[ \"scroll\" + name ], doc[ \"scroll\" + name ],\n\t\t\t\t\t\telem.body[ \"offset\" + name ], doc[ \"offset\" + name ],\n\t\t\t\t\t\tdoc[ \"client\" + name ]\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn value === undefined ?\n\n\t\t\t\t\t// Get width or height on the element, requesting but not forcing parseFloat\n\t\t\t\t\tjQuery.css( elem, type, extra ) :\n\n\t\t\t\t\t// Set width or height on the element\n\t\t\t\t\tjQuery.style( elem, type, value, extra );\n\t\t\t}, type, chainable ? margin : undefined, chainable, null );\n\t\t};\n\t} );\n} );\n\n\njQuery.fn.extend( {\n\n\tbind: function( types, data, fn ) {\n\t\treturn this.on( types, null, data, fn );\n\t},\n\tunbind: function( types, fn ) {\n\t\treturn this.off( types, null, fn );\n\t},\n\n\tdelegate: function( selector, types, data, fn ) {\n\t\treturn this.on( types, selector, data, fn );\n\t},\n\tundelegate: function( selector, types, fn ) {\n\n\t\t// ( namespace ) or ( selector, types [, fn] )\n\t\treturn arguments.length === 1 ?\n\t\t\tthis.off( selector, \"**\" ) :\n\t\t\tthis.off( types, selector || \"**\", fn );\n\t},\n\tsize: function() {\n\t\treturn this.length;\n\t}\n} );\n\njQuery.fn.andSelf = jQuery.fn.addBack;\n\n\n\n\n// Register as a named AMD module, since jQuery can be concatenated with other\n// files that may use define, but not via a proper concatenation script that\n// understands anonymous AMD modules. A named AMD is safest and most robust\n// way to register. Lowercase jquery is used because AMD module names are\n// derived from file names, and jQuery is normally delivered in a lowercase\n// file name. Do this after creating the global so that if an AMD module wants\n// to call noConflict to hide this version of jQuery, it will work.\n\n// Note that for maximum portability, libraries that are not jQuery should\n// declare themselves as anonymous modules, and avoid setting a global if an\n// AMD loader is present. jQuery is a special case. For more information, see\n// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon\n\nif ( typeof define === \"function\" && define.amd ) {\n\tdefine( \"jquery\", [], function() {\n\t\treturn jQuery;\n\t} );\n}\n\n\n\nvar\n\n\t// Map over jQuery in case of overwrite\n\t_jQuery = window.jQuery,\n\n\t// Map over the $ in case of overwrite\n\t_$ = window.$;\n\njQuery.noConflict = function( deep ) {\n\tif ( window.$ === jQuery ) {\n\t\twindow.$ = _$;\n\t}\n\n\tif ( deep && window.jQuery === jQuery ) {\n\t\twindow.jQuery = _jQuery;\n\t}\n\n\treturn jQuery;\n};\n\n// Expose jQuery and $ identifiers, even in AMD\n// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)\n// and CommonJS for browser emulators (#13566)\nif ( !noGlobal ) {\n\twindow.jQuery = window.$ = jQuery;\n}\n\nreturn jQuery;\n}));\n"
  },
  {
    "path": "static_cdn/static_root/admin/js/vendor/xregexp/LICENSE-XREGEXP.txt",
    "content": "The MIT License\n\nCopyright (c) 2007-2012 Steven Levithan <http://xregexp.com/>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "static_cdn/static_root/admin/js/vendor/xregexp/xregexp.js",
    "content": "\n/***** xregexp.js *****/\n\n/*!\n * XRegExp v2.0.0\n * (c) 2007-2012 Steven Levithan <http://xregexp.com/>\n * MIT License\n */\n\n/**\n * XRegExp provides augmented, extensible JavaScript regular expressions. You get new syntax,\n * flags, and methods beyond what browsers support natively. XRegExp is also a regex utility belt\n * with tools to make your client-side grepping simpler and more powerful, while freeing you from\n * worrying about pesky cross-browser inconsistencies and the dubious `lastIndex` property. See\n * XRegExp's documentation (http://xregexp.com/) for more details.\n * @module xregexp\n * @requires N/A\n */\nvar XRegExp;\n\n// Avoid running twice; that would reset tokens and could break references to native globals\nXRegExp = XRegExp || (function (undef) {\n    \"use strict\";\n\n/*--------------------------------------\n *  Private variables\n *------------------------------------*/\n\n    var self,\n        addToken,\n        add,\n\n// Optional features; can be installed and uninstalled\n        features = {\n            natives: false,\n            extensibility: false\n        },\n\n// Store native methods to use and restore (\"native\" is an ES3 reserved keyword)\n        nativ = {\n            exec: RegExp.prototype.exec,\n            test: RegExp.prototype.test,\n            match: String.prototype.match,\n            replace: String.prototype.replace,\n            split: String.prototype.split\n        },\n\n// Storage for fixed/extended native methods\n        fixed = {},\n\n// Storage for cached regexes\n        cache = {},\n\n// Storage for addon tokens\n        tokens = [],\n\n// Token scopes\n        defaultScope = \"default\",\n        classScope = \"class\",\n\n// Regexes that match native regex syntax\n        nativeTokens = {\n            // Any native multicharacter token in default scope (includes octals, excludes character classes)\n            \"default\": /^(?:\\\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\\d*|x[\\dA-Fa-f]{2}|u[\\dA-Fa-f]{4}|c[A-Za-z]|[\\s\\S])|\\(\\?[:=!]|[?*+]\\?|{\\d+(?:,\\d*)?}\\??)/,\n            // Any native multicharacter token in character class scope (includes octals)\n            \"class\": /^(?:\\\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\\dA-Fa-f]{2}|u[\\dA-Fa-f]{4}|c[A-Za-z]|[\\s\\S]))/\n        },\n\n// Any backreference in replacement strings\n        replacementToken = /\\$(?:{([\\w$]+)}|(\\d\\d?|[\\s\\S]))/g,\n\n// Any character with a later instance in the string\n        duplicateFlags = /([\\s\\S])(?=[\\s\\S]*\\1)/g,\n\n// Any greedy/lazy quantifier\n        quantifier = /^(?:[?*+]|{\\d+(?:,\\d*)?})\\??/,\n\n// Check for correct `exec` handling of nonparticipating capturing groups\n        compliantExecNpcg = nativ.exec.call(/()??/, \"\")[1] === undef,\n\n// Check for flag y support (Firefox 3+)\n        hasNativeY = RegExp.prototype.sticky !== undef,\n\n// Used to kill infinite recursion during XRegExp construction\n        isInsideConstructor = false,\n\n// Storage for known flags, including addon flags\n        registeredFlags = \"gim\" + (hasNativeY ? \"y\" : \"\");\n\n/*--------------------------------------\n *  Private helper functions\n *------------------------------------*/\n\n/**\n * Attaches XRegExp.prototype properties and named capture supporting data to a regex object.\n * @private\n * @param {RegExp} regex Regex to augment.\n * @param {Array} captureNames Array with capture names, or null.\n * @param {Boolean} [isNative] Whether the regex was created by `RegExp` rather than `XRegExp`.\n * @returns {RegExp} Augmented regex.\n */\n    function augment(regex, captureNames, isNative) {\n        var p;\n        // Can't auto-inherit these since the XRegExp constructor returns a nonprimitive value\n        for (p in self.prototype) {\n            if (self.prototype.hasOwnProperty(p)) {\n                regex[p] = self.prototype[p];\n            }\n        }\n        regex.xregexp = {captureNames: captureNames, isNative: !!isNative};\n        return regex;\n    }\n\n/**\n * Returns native `RegExp` flags used by a regex object.\n * @private\n * @param {RegExp} regex Regex to check.\n * @returns {String} Native flags in use.\n */\n    function getNativeFlags(regex) {\n        //return nativ.exec.call(/\\/([a-z]*)$/i, String(regex))[1];\n        return (regex.global     ? \"g\" : \"\") +\n               (regex.ignoreCase ? \"i\" : \"\") +\n               (regex.multiline  ? \"m\" : \"\") +\n               (regex.extended   ? \"x\" : \"\") + // Proposed for ES6, included in AS3\n               (regex.sticky     ? \"y\" : \"\"); // Proposed for ES6, included in Firefox 3+\n    }\n\n/**\n * Copies a regex object while preserving special properties for named capture and augmenting with\n * `XRegExp.prototype` methods. The copy has a fresh `lastIndex` property (set to zero). Allows\n * adding and removing flags while copying the regex.\n * @private\n * @param {RegExp} regex Regex to copy.\n * @param {String} [addFlags] Flags to be added while copying the regex.\n * @param {String} [removeFlags] Flags to be removed while copying the regex.\n * @returns {RegExp} Copy of the provided regex, possibly with modified flags.\n */\n    function copy(regex, addFlags, removeFlags) {\n        if (!self.isRegExp(regex)) {\n            throw new TypeError(\"type RegExp expected\");\n        }\n        var flags = nativ.replace.call(getNativeFlags(regex) + (addFlags || \"\"), duplicateFlags, \"\");\n        if (removeFlags) {\n            // Would need to escape `removeFlags` if this was public\n            flags = nativ.replace.call(flags, new RegExp(\"[\" + removeFlags + \"]+\", \"g\"), \"\");\n        }\n        if (regex.xregexp && !regex.xregexp.isNative) {\n            // Compiling the current (rather than precompilation) source preserves the effects of nonnative source flags\n            regex = augment(self(regex.source, flags),\n                            regex.xregexp.captureNames ? regex.xregexp.captureNames.slice(0) : null);\n        } else {\n            // Augment with `XRegExp.prototype` methods, but use native `RegExp` (avoid searching for special tokens)\n            regex = augment(new RegExp(regex.source, flags), null, true);\n        }\n        return regex;\n    }\n\n/*\n * Returns the last index at which a given value can be found in an array, or `-1` if it's not\n * present. The array is searched backwards.\n * @private\n * @param {Array} array Array to search.\n * @param {*} value Value to locate in the array.\n * @returns {Number} Last zero-based index at which the item is found, or -1.\n */\n    function lastIndexOf(array, value) {\n        var i = array.length;\n        if (Array.prototype.lastIndexOf) {\n            return array.lastIndexOf(value); // Use the native method if available\n        }\n        while (i--) {\n            if (array[i] === value) {\n                return i;\n            }\n        }\n        return -1;\n    }\n\n/**\n * Determines whether an object is of the specified type.\n * @private\n * @param {*} value Object to check.\n * @param {String} type Type to check for, in lowercase.\n * @returns {Boolean} Whether the object matches the type.\n */\n    function isType(value, type) {\n        return Object.prototype.toString.call(value).toLowerCase() === \"[object \" + type + \"]\";\n    }\n\n/**\n * Prepares an options object from the given value.\n * @private\n * @param {String|Object} value Value to convert to an options object.\n * @returns {Object} Options object.\n */\n    function prepareOptions(value) {\n        value = value || {};\n        if (value === \"all\" || value.all) {\n            value = {natives: true, extensibility: true};\n        } else if (isType(value, \"string\")) {\n            value = self.forEach(value, /[^\\s,]+/, function (m) {\n                this[m] = true;\n            }, {});\n        }\n        return value;\n    }\n\n/**\n * Runs built-in/custom tokens in reverse insertion order, until a match is found.\n * @private\n * @param {String} pattern Original pattern from which an XRegExp object is being built.\n * @param {Number} pos Position to search for tokens within `pattern`.\n * @param {Number} scope Current regex scope.\n * @param {Object} context Context object assigned to token handler functions.\n * @returns {Object} Object with properties `output` (the substitution string returned by the\n *   successful token handler) and `match` (the token's match array), or null.\n */\n    function runTokens(pattern, pos, scope, context) {\n        var i = tokens.length,\n            result = null,\n            match,\n            t;\n        // Protect against constructing XRegExps within token handler and trigger functions\n        isInsideConstructor = true;\n        // Must reset `isInsideConstructor`, even if a `trigger` or `handler` throws\n        try {\n            while (i--) { // Run in reverse order\n                t = tokens[i];\n                if ((t.scope === \"all\" || t.scope === scope) && (!t.trigger || t.trigger.call(context))) {\n                    t.pattern.lastIndex = pos;\n                    match = fixed.exec.call(t.pattern, pattern); // Fixed `exec` here allows use of named backreferences, etc.\n                    if (match && match.index === pos) {\n                        result = {\n                            output: t.handler.call(context, match, scope),\n                            match: match\n                        };\n                        break;\n                    }\n                }\n            }\n        } catch (err) {\n            throw err;\n        } finally {\n            isInsideConstructor = false;\n        }\n        return result;\n    }\n\n/**\n * Enables or disables XRegExp syntax and flag extensibility.\n * @private\n * @param {Boolean} on `true` to enable; `false` to disable.\n */\n    function setExtensibility(on) {\n        self.addToken = addToken[on ? \"on\" : \"off\"];\n        features.extensibility = on;\n    }\n\n/**\n * Enables or disables native method overrides.\n * @private\n * @param {Boolean} on `true` to enable; `false` to disable.\n */\n    function setNatives(on) {\n        RegExp.prototype.exec = (on ? fixed : nativ).exec;\n        RegExp.prototype.test = (on ? fixed : nativ).test;\n        String.prototype.match = (on ? fixed : nativ).match;\n        String.prototype.replace = (on ? fixed : nativ).replace;\n        String.prototype.split = (on ? fixed : nativ).split;\n        features.natives = on;\n    }\n\n/*--------------------------------------\n *  Constructor\n *------------------------------------*/\n\n/**\n * Creates an extended regular expression object for matching text with a pattern. Differs from a\n * native regular expression in that additional syntax and flags are supported. The returned object\n * is in fact a native `RegExp` and works with all native methods.\n * @class XRegExp\n * @constructor\n * @param {String|RegExp} pattern Regex pattern string, or an existing `RegExp` object to copy.\n * @param {String} [flags] Any combination of flags:\n *   <li>`g` - global\n *   <li>`i` - ignore case\n *   <li>`m` - multiline anchors\n *   <li>`n` - explicit capture\n *   <li>`s` - dot matches all (aka singleline)\n *   <li>`x` - free-spacing and line comments (aka extended)\n *   <li>`y` - sticky (Firefox 3+ only)\n *   Flags cannot be provided when constructing one `RegExp` from another.\n * @returns {RegExp} Extended regular expression object.\n * @example\n *\n * // With named capture and flag x\n * date = XRegExp('(?<year>  [0-9]{4}) -?  # year  \\n\\\n *                 (?<month> [0-9]{2}) -?  # month \\n\\\n *                 (?<day>   [0-9]{2})     # day   ', 'x');\n *\n * // Passing a regex object to copy it. The copy maintains special properties for named capture,\n * // is augmented with `XRegExp.prototype` methods, and has a fresh `lastIndex` property (set to\n * // zero). Native regexes are not recompiled using XRegExp syntax.\n * XRegExp(/regex/);\n */\n    self = function (pattern, flags) {\n        if (self.isRegExp(pattern)) {\n            if (flags !== undef) {\n                throw new TypeError(\"can't supply flags when constructing one RegExp from another\");\n            }\n            return copy(pattern);\n        }\n        // Tokens become part of the regex construction process, so protect against infinite recursion\n        // when an XRegExp is constructed within a token handler function\n        if (isInsideConstructor) {\n            throw new Error(\"can't call the XRegExp constructor within token definition functions\");\n        }\n\n        var output = [],\n            scope = defaultScope,\n            tokenContext = {\n                hasNamedCapture: false,\n                captureNames: [],\n                hasFlag: function (flag) {\n                    return flags.indexOf(flag) > -1;\n                }\n            },\n            pos = 0,\n            tokenResult,\n            match,\n            chr;\n        pattern = pattern === undef ? \"\" : String(pattern);\n        flags = flags === undef ? \"\" : String(flags);\n\n        if (nativ.match.call(flags, duplicateFlags)) { // Don't use test/exec because they would update lastIndex\n            throw new SyntaxError(\"invalid duplicate regular expression flag\");\n        }\n        // Strip/apply leading mode modifier with any combination of flags except g or y: (?imnsx)\n        pattern = nativ.replace.call(pattern, /^\\(\\?([\\w$]+)\\)/, function ($0, $1) {\n            if (nativ.test.call(/[gy]/, $1)) {\n                throw new SyntaxError(\"can't use flag g or y in mode modifier\");\n            }\n            flags = nativ.replace.call(flags + $1, duplicateFlags, \"\");\n            return \"\";\n        });\n        self.forEach(flags, /[\\s\\S]/, function (m) {\n            if (registeredFlags.indexOf(m[0]) < 0) {\n                throw new SyntaxError(\"invalid regular expression flag \" + m[0]);\n            }\n        });\n\n        while (pos < pattern.length) {\n            // Check for custom tokens at the current position\n            tokenResult = runTokens(pattern, pos, scope, tokenContext);\n            if (tokenResult) {\n                output.push(tokenResult.output);\n                pos += (tokenResult.match[0].length || 1);\n            } else {\n                // Check for native tokens (except character classes) at the current position\n                match = nativ.exec.call(nativeTokens[scope], pattern.slice(pos));\n                if (match) {\n                    output.push(match[0]);\n                    pos += match[0].length;\n                } else {\n                    chr = pattern.charAt(pos);\n                    if (chr === \"[\") {\n                        scope = classScope;\n                    } else if (chr === \"]\") {\n                        scope = defaultScope;\n                    }\n                    // Advance position by one character\n                    output.push(chr);\n                    ++pos;\n                }\n            }\n        }\n\n        return augment(new RegExp(output.join(\"\"), nativ.replace.call(flags, /[^gimy]+/g, \"\")),\n                       tokenContext.hasNamedCapture ? tokenContext.captureNames : null);\n    };\n\n/*--------------------------------------\n *  Public methods/properties\n *------------------------------------*/\n\n// Installed and uninstalled states for `XRegExp.addToken`\n    addToken = {\n        on: function (regex, handler, options) {\n            options = options || {};\n            if (regex) {\n                tokens.push({\n                    pattern: copy(regex, \"g\" + (hasNativeY ? \"y\" : \"\")),\n                    handler: handler,\n                    scope: options.scope || defaultScope,\n                    trigger: options.trigger || null\n                });\n            }\n            // Providing `customFlags` with null `regex` and `handler` allows adding flags that do\n            // nothing, but don't throw an error\n            if (options.customFlags) {\n                registeredFlags = nativ.replace.call(registeredFlags + options.customFlags, duplicateFlags, \"\");\n            }\n        },\n        off: function () {\n            throw new Error(\"extensibility must be installed before using addToken\");\n        }\n    };\n\n/**\n * Extends or changes XRegExp syntax and allows custom flags. This is used internally and can be\n * used to create XRegExp addons. `XRegExp.install('extensibility')` must be run before calling\n * this function, or an error is thrown. If more than one token can match the same string, the last\n * added wins.\n * @memberOf XRegExp\n * @param {RegExp} regex Regex object that matches the new token.\n * @param {Function} handler Function that returns a new pattern string (using native regex syntax)\n *   to replace the matched token within all future XRegExp regexes. Has access to persistent\n *   properties of the regex being built, through `this`. Invoked with two arguments:\n *   <li>The match array, with named backreference properties.\n *   <li>The regex scope where the match was found.\n * @param {Object} [options] Options object with optional properties:\n *   <li>`scope` {String} Scopes where the token applies: 'default', 'class', or 'all'.\n *   <li>`trigger` {Function} Function that returns `true` when the token should be applied; e.g.,\n *     if a flag is set. If `false` is returned, the matched string can be matched by other tokens.\n *     Has access to persistent properties of the regex being built, through `this` (including\n *     function `this.hasFlag`).\n *   <li>`customFlags` {String} Nonnative flags used by the token's handler or trigger functions.\n *     Prevents XRegExp from throwing an invalid flag error when the specified flags are used.\n * @example\n *\n * // Basic usage: Adds \\a for ALERT character\n * XRegExp.addToken(\n *   /\\\\a/,\n *   function () {return '\\\\x07';},\n *   {scope: 'all'}\n * );\n * XRegExp('\\\\a[\\\\a-\\\\n]+').test('\\x07\\n\\x07'); // -> true\n */\n    self.addToken = addToken.off;\n\n/**\n * Caches and returns the result of calling `XRegExp(pattern, flags)`. On any subsequent call with\n * the same pattern and flag combination, the cached copy is returned.\n * @memberOf XRegExp\n * @param {String} pattern Regex pattern string.\n * @param {String} [flags] Any combination of XRegExp flags.\n * @returns {RegExp} Cached XRegExp object.\n * @example\n *\n * while (match = XRegExp.cache('.', 'gs').exec(str)) {\n *   // The regex is compiled once only\n * }\n */\n    self.cache = function (pattern, flags) {\n        var key = pattern + \"/\" + (flags || \"\");\n        return cache[key] || (cache[key] = self(pattern, flags));\n    };\n\n/**\n * Escapes any regular expression metacharacters, for use when matching literal strings. The result\n * can safely be used at any point within a regex that uses any flags.\n * @memberOf XRegExp\n * @param {String} str String to escape.\n * @returns {String} String with regex metacharacters escaped.\n * @example\n *\n * XRegExp.escape('Escaped? <.>');\n * // -> 'Escaped\\?\\ <\\.>'\n */\n    self.escape = function (str) {\n        return nativ.replace.call(str, /[-[\\]{}()*+?.,\\\\^$|#\\s]/g, \"\\\\$&\");\n    };\n\n/**\n * Executes a regex search in a specified string. Returns a match array or `null`. If the provided\n * regex uses named capture, named backreference properties are included on the match array.\n * Optional `pos` and `sticky` arguments specify the search start position, and whether the match\n * must start at the specified position only. The `lastIndex` property of the provided regex is not\n * used, but is updated for compatibility. Also fixes browser bugs compared to the native\n * `RegExp.prototype.exec` and can be used reliably cross-browser.\n * @memberOf XRegExp\n * @param {String} str String to search.\n * @param {RegExp} regex Regex to search with.\n * @param {Number} [pos=0] Zero-based index at which to start the search.\n * @param {Boolean|String} [sticky=false] Whether the match must start at the specified position\n *   only. The string `'sticky'` is accepted as an alternative to `true`.\n * @returns {Array} Match array with named backreference properties, or null.\n * @example\n *\n * // Basic use, with named backreference\n * var match = XRegExp.exec('U+2620', XRegExp('U\\\\+(?<hex>[0-9A-F]{4})'));\n * match.hex; // -> '2620'\n *\n * // With pos and sticky, in a loop\n * var pos = 2, result = [], match;\n * while (match = XRegExp.exec('<1><2><3><4>5<6>', /<(\\d)>/, pos, 'sticky')) {\n *   result.push(match[1]);\n *   pos = match.index + match[0].length;\n * }\n * // result -> ['2', '3', '4']\n */\n    self.exec = function (str, regex, pos, sticky) {\n        var r2 = copy(regex, \"g\" + (sticky && hasNativeY ? \"y\" : \"\"), (sticky === false ? \"y\" : \"\")),\n            match;\n        r2.lastIndex = pos = pos || 0;\n        match = fixed.exec.call(r2, str); // Fixed `exec` required for `lastIndex` fix, etc.\n        if (sticky && match && match.index !== pos) {\n            match = null;\n        }\n        if (regex.global) {\n            regex.lastIndex = match ? r2.lastIndex : 0;\n        }\n        return match;\n    };\n\n/**\n * Executes a provided function once per regex match.\n * @memberOf XRegExp\n * @param {String} str String to search.\n * @param {RegExp} regex Regex to search with.\n * @param {Function} callback Function to execute for each match. Invoked with four arguments:\n *   <li>The match array, with named backreference properties.\n *   <li>The zero-based match index.\n *   <li>The string being traversed.\n *   <li>The regex object being used to traverse the string.\n * @param {*} [context] Object to use as `this` when executing `callback`.\n * @returns {*} Provided `context` object.\n * @example\n *\n * // Extracts every other digit from a string\n * XRegExp.forEach('1a2345', /\\d/, function (match, i) {\n *   if (i % 2) this.push(+match[0]);\n * }, []);\n * // -> [2, 4]\n */\n    self.forEach = function (str, regex, callback, context) {\n        var pos = 0,\n            i = -1,\n            match;\n        while ((match = self.exec(str, regex, pos))) {\n            callback.call(context, match, ++i, str, regex);\n            pos = match.index + (match[0].length || 1);\n        }\n        return context;\n    };\n\n/**\n * Copies a regex object and adds flag `g`. The copy maintains special properties for named\n * capture, is augmented with `XRegExp.prototype` methods, and has a fresh `lastIndex` property\n * (set to zero). Native regexes are not recompiled using XRegExp syntax.\n * @memberOf XRegExp\n * @param {RegExp} regex Regex to globalize.\n * @returns {RegExp} Copy of the provided regex with flag `g` added.\n * @example\n *\n * var globalCopy = XRegExp.globalize(/regex/);\n * globalCopy.global; // -> true\n */\n    self.globalize = function (regex) {\n        return copy(regex, \"g\");\n    };\n\n/**\n * Installs optional features according to the specified options.\n * @memberOf XRegExp\n * @param {Object|String} options Options object or string.\n * @example\n *\n * // With an options object\n * XRegExp.install({\n *   // Overrides native regex methods with fixed/extended versions that support named\n *   // backreferences and fix numerous cross-browser bugs\n *   natives: true,\n *\n *   // Enables extensibility of XRegExp syntax and flags\n *   extensibility: true\n * });\n *\n * // With an options string\n * XRegExp.install('natives extensibility');\n *\n * // Using a shortcut to install all optional features\n * XRegExp.install('all');\n */\n    self.install = function (options) {\n        options = prepareOptions(options);\n        if (!features.natives && options.natives) {\n            setNatives(true);\n        }\n        if (!features.extensibility && options.extensibility) {\n            setExtensibility(true);\n        }\n    };\n\n/**\n * Checks whether an individual optional feature is installed.\n * @memberOf XRegExp\n * @param {String} feature Name of the feature to check. One of:\n *   <li>`natives`\n *   <li>`extensibility`\n * @returns {Boolean} Whether the feature is installed.\n * @example\n *\n * XRegExp.isInstalled('natives');\n */\n    self.isInstalled = function (feature) {\n        return !!(features[feature]);\n    };\n\n/**\n * Returns `true` if an object is a regex; `false` if it isn't. This works correctly for regexes\n * created in another frame, when `instanceof` and `constructor` checks would fail.\n * @memberOf XRegExp\n * @param {*} value Object to check.\n * @returns {Boolean} Whether the object is a `RegExp` object.\n * @example\n *\n * XRegExp.isRegExp('string'); // -> false\n * XRegExp.isRegExp(/regex/i); // -> true\n * XRegExp.isRegExp(RegExp('^', 'm')); // -> true\n * XRegExp.isRegExp(XRegExp('(?s).')); // -> true\n */\n    self.isRegExp = function (value) {\n        return isType(value, \"regexp\");\n    };\n\n/**\n * Retrieves the matches from searching a string using a chain of regexes that successively search\n * within previous matches. The provided `chain` array can contain regexes and objects with `regex`\n * and `backref` properties. When a backreference is specified, the named or numbered backreference\n * is passed forward to the next regex or returned.\n * @memberOf XRegExp\n * @param {String} str String to search.\n * @param {Array} chain Regexes that each search for matches within preceding results.\n * @returns {Array} Matches by the last regex in the chain, or an empty array.\n * @example\n *\n * // Basic usage; matches numbers within <b> tags\n * XRegExp.matchChain('1 <b>2</b> 3 <b>4 a 56</b>', [\n *   XRegExp('(?is)<b>.*?</b>'),\n *   /\\d+/\n * ]);\n * // -> ['2', '4', '56']\n *\n * // Passing forward and returning specific backreferences\n * html = '<a href=\"http://xregexp.com/api/\">XRegExp</a>\\\n *         <a href=\"http://www.google.com/\">Google</a>';\n * XRegExp.matchChain(html, [\n *   {regex: /<a href=\"([^\"]+)\">/i, backref: 1},\n *   {regex: XRegExp('(?i)^https?://(?<domain>[^/?#]+)'), backref: 'domain'}\n * ]);\n * // -> ['xregexp.com', 'www.google.com']\n */\n    self.matchChain = function (str, chain) {\n        return (function recurseChain(values, level) {\n            var item = chain[level].regex ? chain[level] : {regex: chain[level]},\n                matches = [],\n                addMatch = function (match) {\n                    matches.push(item.backref ? (match[item.backref] || \"\") : match[0]);\n                },\n                i;\n            for (i = 0; i < values.length; ++i) {\n                self.forEach(values[i], item.regex, addMatch);\n            }\n            return ((level === chain.length - 1) || !matches.length) ?\n                    matches :\n                    recurseChain(matches, level + 1);\n        }([str], 0));\n    };\n\n/**\n * Returns a new string with one or all matches of a pattern replaced. The pattern can be a string\n * or regex, and the replacement can be a string or a function to be called for each match. To\n * perform a global search and replace, use the optional `scope` argument or include flag `g` if\n * using a regex. Replacement strings can use `${n}` for named and numbered backreferences.\n * Replacement functions can use named backreferences via `arguments[0].name`. Also fixes browser\n * bugs compared to the native `String.prototype.replace` and can be used reliably cross-browser.\n * @memberOf XRegExp\n * @param {String} str String to search.\n * @param {RegExp|String} search Search pattern to be replaced.\n * @param {String|Function} replacement Replacement string or a function invoked to create it.\n *   Replacement strings can include special replacement syntax:\n *     <li>$$ - Inserts a literal '$'.\n *     <li>$&, $0 - Inserts the matched substring.\n *     <li>$` - Inserts the string that precedes the matched substring (left context).\n *     <li>$' - Inserts the string that follows the matched substring (right context).\n *     <li>$n, $nn - Where n/nn are digits referencing an existent capturing group, inserts\n *       backreference n/nn.\n *     <li>${n} - Where n is a name or any number of digits that reference an existent capturing\n *       group, inserts backreference n.\n *   Replacement functions are invoked with three or more arguments:\n *     <li>The matched substring (corresponds to $& above). Named backreferences are accessible as\n *       properties of this first argument.\n *     <li>0..n arguments, one for each backreference (corresponding to $1, $2, etc. above).\n *     <li>The zero-based index of the match within the total search string.\n *     <li>The total string being searched.\n * @param {String} [scope='one'] Use 'one' to replace the first match only, or 'all'. If not\n *   explicitly specified and using a regex with flag `g`, `scope` is 'all'.\n * @returns {String} New string with one or all matches replaced.\n * @example\n *\n * // Regex search, using named backreferences in replacement string\n * var name = XRegExp('(?<first>\\\\w+) (?<last>\\\\w+)');\n * XRegExp.replace('John Smith', name, '${last}, ${first}');\n * // -> 'Smith, John'\n *\n * // Regex search, using named backreferences in replacement function\n * XRegExp.replace('John Smith', name, function (match) {\n *   return match.last + ', ' + match.first;\n * });\n * // -> 'Smith, John'\n *\n * // Global string search/replacement\n * XRegExp.replace('RegExp builds RegExps', 'RegExp', 'XRegExp', 'all');\n * // -> 'XRegExp builds XRegExps'\n */\n    self.replace = function (str, search, replacement, scope) {\n        var isRegex = self.isRegExp(search),\n            search2 = search,\n            result;\n        if (isRegex) {\n            if (scope === undef && search.global) {\n                scope = \"all\"; // Follow flag g when `scope` isn't explicit\n            }\n            // Note that since a copy is used, `search`'s `lastIndex` isn't updated *during* replacement iterations\n            search2 = copy(search, scope === \"all\" ? \"g\" : \"\", scope === \"all\" ? \"\" : \"g\");\n        } else if (scope === \"all\") {\n            search2 = new RegExp(self.escape(String(search)), \"g\");\n        }\n        result = fixed.replace.call(String(str), search2, replacement); // Fixed `replace` required for named backreferences, etc.\n        if (isRegex && search.global) {\n            search.lastIndex = 0; // Fixes IE, Safari bug (last tested IE 9, Safari 5.1)\n        }\n        return result;\n    };\n\n/**\n * Splits a string into an array of strings using a regex or string separator. Matches of the\n * separator are not included in the result array. However, if `separator` is a regex that contains\n * capturing groups, backreferences are spliced into the result each time `separator` is matched.\n * Fixes browser bugs compared to the native `String.prototype.split` and can be used reliably\n * cross-browser.\n * @memberOf XRegExp\n * @param {String} str String to split.\n * @param {RegExp|String} separator Regex or string to use for separating the string.\n * @param {Number} [limit] Maximum number of items to include in the result array.\n * @returns {Array} Array of substrings.\n * @example\n *\n * // Basic use\n * XRegExp.split('a b c', ' ');\n * // -> ['a', 'b', 'c']\n *\n * // With limit\n * XRegExp.split('a b c', ' ', 2);\n * // -> ['a', 'b']\n *\n * // Backreferences in result array\n * XRegExp.split('..word1..', /([a-z]+)(\\d+)/i);\n * // -> ['..', 'word', '1', '..']\n */\n    self.split = function (str, separator, limit) {\n        return fixed.split.call(str, separator, limit);\n    };\n\n/**\n * Executes a regex search in a specified string. Returns `true` or `false`. Optional `pos` and\n * `sticky` arguments specify the search start position, and whether the match must start at the\n * specified position only. The `lastIndex` property of the provided regex is not used, but is\n * updated for compatibility. Also fixes browser bugs compared to the native\n * `RegExp.prototype.test` and can be used reliably cross-browser.\n * @memberOf XRegExp\n * @param {String} str String to search.\n * @param {RegExp} regex Regex to search with.\n * @param {Number} [pos=0] Zero-based index at which to start the search.\n * @param {Boolean|String} [sticky=false] Whether the match must start at the specified position\n *   only. The string `'sticky'` is accepted as an alternative to `true`.\n * @returns {Boolean} Whether the regex matched the provided value.\n * @example\n *\n * // Basic use\n * XRegExp.test('abc', /c/); // -> true\n *\n * // With pos and sticky\n * XRegExp.test('abc', /c/, 0, 'sticky'); // -> false\n */\n    self.test = function (str, regex, pos, sticky) {\n        // Do this the easy way :-)\n        return !!self.exec(str, regex, pos, sticky);\n    };\n\n/**\n * Uninstalls optional features according to the specified options.\n * @memberOf XRegExp\n * @param {Object|String} options Options object or string.\n * @example\n *\n * // With an options object\n * XRegExp.uninstall({\n *   // Restores native regex methods\n *   natives: true,\n *\n *   // Disables additional syntax and flag extensions\n *   extensibility: true\n * });\n *\n * // With an options string\n * XRegExp.uninstall('natives extensibility');\n *\n * // Using a shortcut to uninstall all optional features\n * XRegExp.uninstall('all');\n */\n    self.uninstall = function (options) {\n        options = prepareOptions(options);\n        if (features.natives && options.natives) {\n            setNatives(false);\n        }\n        if (features.extensibility && options.extensibility) {\n            setExtensibility(false);\n        }\n    };\n\n/**\n * Returns an XRegExp object that is the union of the given patterns. Patterns can be provided as\n * regex objects or strings. Metacharacters are escaped in patterns provided as strings.\n * Backreferences in provided regex objects are automatically renumbered to work correctly. Native\n * flags used by provided regexes are ignored in favor of the `flags` argument.\n * @memberOf XRegExp\n * @param {Array} patterns Regexes and strings to combine.\n * @param {String} [flags] Any combination of XRegExp flags.\n * @returns {RegExp} Union of the provided regexes and strings.\n * @example\n *\n * XRegExp.union(['a+b*c', /(dogs)\\1/, /(cats)\\1/], 'i');\n * // -> /a\\+b\\*c|(dogs)\\1|(cats)\\2/i\n *\n * XRegExp.union([XRegExp('(?<pet>dogs)\\\\k<pet>'), XRegExp('(?<pet>cats)\\\\k<pet>')]);\n * // -> XRegExp('(?<pet>dogs)\\\\k<pet>|(?<pet>cats)\\\\k<pet>')\n */\n    self.union = function (patterns, flags) {\n        var parts = /(\\()(?!\\?)|\\\\([1-9]\\d*)|\\\\[\\s\\S]|\\[(?:[^\\\\\\]]|\\\\[\\s\\S])*]/g,\n            numCaptures = 0,\n            numPriorCaptures,\n            captureNames,\n            rewrite = function (match, paren, backref) {\n                var name = captureNames[numCaptures - numPriorCaptures];\n                if (paren) { // Capturing group\n                    ++numCaptures;\n                    if (name) { // If the current capture has a name\n                        return \"(?<\" + name + \">\";\n                    }\n                } else if (backref) { // Backreference\n                    return \"\\\\\" + (+backref + numPriorCaptures);\n                }\n                return match;\n            },\n            output = [],\n            pattern,\n            i;\n        if (!(isType(patterns, \"array\") && patterns.length)) {\n            throw new TypeError(\"patterns must be a nonempty array\");\n        }\n        for (i = 0; i < patterns.length; ++i) {\n            pattern = patterns[i];\n            if (self.isRegExp(pattern)) {\n                numPriorCaptures = numCaptures;\n                captureNames = (pattern.xregexp && pattern.xregexp.captureNames) || [];\n                // Rewrite backreferences. Passing to XRegExp dies on octals and ensures patterns\n                // are independently valid; helps keep this simple. Named captures are put back\n                output.push(self(pattern.source).source.replace(parts, rewrite));\n            } else {\n                output.push(self.escape(pattern));\n            }\n        }\n        return self(output.join(\"|\"), flags);\n    };\n\n/**\n * The XRegExp version number.\n * @static\n * @memberOf XRegExp\n * @type String\n */\n    self.version = \"2.0.0\";\n\n/*--------------------------------------\n *  Fixed/extended native methods\n *------------------------------------*/\n\n/**\n * Adds named capture support (with backreferences returned as `result.name`), and fixes browser\n * bugs in the native `RegExp.prototype.exec`. Calling `XRegExp.install('natives')` uses this to\n * override the native method. Use via `XRegExp.exec` without overriding natives.\n * @private\n * @param {String} str String to search.\n * @returns {Array} Match array with named backreference properties, or null.\n */\n    fixed.exec = function (str) {\n        var match, name, r2, origLastIndex, i;\n        if (!this.global) {\n            origLastIndex = this.lastIndex;\n        }\n        match = nativ.exec.apply(this, arguments);\n        if (match) {\n            // Fix browsers whose `exec` methods don't consistently return `undefined` for\n            // nonparticipating capturing groups\n            if (!compliantExecNpcg && match.length > 1 && lastIndexOf(match, \"\") > -1) {\n                r2 = new RegExp(this.source, nativ.replace.call(getNativeFlags(this), \"g\", \"\"));\n                // Using `str.slice(match.index)` rather than `match[0]` in case lookahead allowed\n                // matching due to characters outside the match\n                nativ.replace.call(String(str).slice(match.index), r2, function () {\n                    var i;\n                    for (i = 1; i < arguments.length - 2; ++i) {\n                        if (arguments[i] === undef) {\n                            match[i] = undef;\n                        }\n                    }\n                });\n            }\n            // Attach named capture properties\n            if (this.xregexp && this.xregexp.captureNames) {\n                for (i = 1; i < match.length; ++i) {\n                    name = this.xregexp.captureNames[i - 1];\n                    if (name) {\n                        match[name] = match[i];\n                    }\n                }\n            }\n            // Fix browsers that increment `lastIndex` after zero-length matches\n            if (this.global && !match[0].length && (this.lastIndex > match.index)) {\n                this.lastIndex = match.index;\n            }\n        }\n        if (!this.global) {\n            this.lastIndex = origLastIndex; // Fixes IE, Opera bug (last tested IE 9, Opera 11.6)\n        }\n        return match;\n    };\n\n/**\n * Fixes browser bugs in the native `RegExp.prototype.test`. Calling `XRegExp.install('natives')`\n * uses this to override the native method.\n * @private\n * @param {String} str String to search.\n * @returns {Boolean} Whether the regex matched the provided value.\n */\n    fixed.test = function (str) {\n        // Do this the easy way :-)\n        return !!fixed.exec.call(this, str);\n    };\n\n/**\n * Adds named capture support (with backreferences returned as `result.name`), and fixes browser\n * bugs in the native `String.prototype.match`. Calling `XRegExp.install('natives')` uses this to\n * override the native method.\n * @private\n * @param {RegExp} regex Regex to search with.\n * @returns {Array} If `regex` uses flag g, an array of match strings or null. Without flag g, the\n *   result of calling `regex.exec(this)`.\n */\n    fixed.match = function (regex) {\n        if (!self.isRegExp(regex)) {\n            regex = new RegExp(regex); // Use native `RegExp`\n        } else if (regex.global) {\n            var result = nativ.match.apply(this, arguments);\n            regex.lastIndex = 0; // Fixes IE bug\n            return result;\n        }\n        return fixed.exec.call(regex, this);\n    };\n\n/**\n * Adds support for `${n}` tokens for named and numbered backreferences in replacement text, and\n * provides named backreferences to replacement functions as `arguments[0].name`. Also fixes\n * browser bugs in replacement text syntax when performing a replacement using a nonregex search\n * value, and the value of a replacement regex's `lastIndex` property during replacement iterations\n * and upon completion. Note that this doesn't support SpiderMonkey's proprietary third (`flags`)\n * argument. Calling `XRegExp.install('natives')` uses this to override the native method. Use via\n * `XRegExp.replace` without overriding natives.\n * @private\n * @param {RegExp|String} search Search pattern to be replaced.\n * @param {String|Function} replacement Replacement string or a function invoked to create it.\n * @returns {String} New string with one or all matches replaced.\n */\n    fixed.replace = function (search, replacement) {\n        var isRegex = self.isRegExp(search), captureNames, result, str, origLastIndex;\n        if (isRegex) {\n            if (search.xregexp) {\n                captureNames = search.xregexp.captureNames;\n            }\n            if (!search.global) {\n                origLastIndex = search.lastIndex;\n            }\n        } else {\n            search += \"\";\n        }\n        if (isType(replacement, \"function\")) {\n            result = nativ.replace.call(String(this), search, function () {\n                var args = arguments, i;\n                if (captureNames) {\n                    // Change the `arguments[0]` string primitive to a `String` object that can store properties\n                    args[0] = new String(args[0]);\n                    // Store named backreferences on the first argument\n                    for (i = 0; i < captureNames.length; ++i) {\n                        if (captureNames[i]) {\n                            args[0][captureNames[i]] = args[i + 1];\n                        }\n                    }\n                }\n                // Update `lastIndex` before calling `replacement`.\n                // Fixes IE, Chrome, Firefox, Safari bug (last tested IE 9, Chrome 17, Firefox 11, Safari 5.1)\n                if (isRegex && search.global) {\n                    search.lastIndex = args[args.length - 2] + args[0].length;\n                }\n                return replacement.apply(null, args);\n            });\n        } else {\n            str = String(this); // Ensure `args[args.length - 1]` will be a string when given nonstring `this`\n            result = nativ.replace.call(str, search, function () {\n                var args = arguments; // Keep this function's `arguments` available through closure\n                return nativ.replace.call(String(replacement), replacementToken, function ($0, $1, $2) {\n                    var n;\n                    // Named or numbered backreference with curly brackets\n                    if ($1) {\n                        /* XRegExp behavior for `${n}`:\n                         * 1. Backreference to numbered capture, where `n` is 1+ digits. `0`, `00`, etc. is the entire match.\n                         * 2. Backreference to named capture `n`, if it exists and is not a number overridden by numbered capture.\n                         * 3. Otherwise, it's an error.\n                         */\n                        n = +$1; // Type-convert; drop leading zeros\n                        if (n <= args.length - 3) {\n                            return args[n] || \"\";\n                        }\n                        n = captureNames ? lastIndexOf(captureNames, $1) : -1;\n                        if (n < 0) {\n                            throw new SyntaxError(\"backreference to undefined group \" + $0);\n                        }\n                        return args[n + 1] || \"\";\n                    }\n                    // Else, special variable or numbered backreference (without curly brackets)\n                    if ($2 === \"$\") return \"$\";\n                    if ($2 === \"&\" || +$2 === 0) return args[0]; // $&, $0 (not followed by 1-9), $00\n                    if ($2 === \"`\") return args[args.length - 1].slice(0, args[args.length - 2]);\n                    if ($2 === \"'\") return args[args.length - 1].slice(args[args.length - 2] + args[0].length);\n                    // Else, numbered backreference (without curly brackets)\n                    $2 = +$2; // Type-convert; drop leading zero\n                    /* XRegExp behavior:\n                     * - Backreferences without curly brackets end after 1 or 2 digits. Use `${..}` for more digits.\n                     * - `$1` is an error if there are no capturing groups.\n                     * - `$10` is an error if there are less than 10 capturing groups. Use `${1}0` instead.\n                     * - `$01` is equivalent to `$1` if a capturing group exists, otherwise it's an error.\n                     * - `$0` (not followed by 1-9), `$00`, and `$&` are the entire match.\n                     * Native behavior, for comparison:\n                     * - Backreferences end after 1 or 2 digits. Cannot use backreference to capturing group 100+.\n                     * - `$1` is a literal `$1` if there are no capturing groups.\n                     * - `$10` is `$1` followed by a literal `0` if there are less than 10 capturing groups.\n                     * - `$01` is equivalent to `$1` if a capturing group exists, otherwise it's a literal `$01`.\n                     * - `$0` is a literal `$0`. `$&` is the entire match.\n                     */\n                    if (!isNaN($2)) {\n                        if ($2 > args.length - 3) {\n                            throw new SyntaxError(\"backreference to undefined group \" + $0);\n                        }\n                        return args[$2] || \"\";\n                    }\n                    throw new SyntaxError(\"invalid token \" + $0);\n                });\n            });\n        }\n        if (isRegex) {\n            if (search.global) {\n                search.lastIndex = 0; // Fixes IE, Safari bug (last tested IE 9, Safari 5.1)\n            } else {\n                search.lastIndex = origLastIndex; // Fixes IE, Opera bug (last tested IE 9, Opera 11.6)\n            }\n        }\n        return result;\n    };\n\n/**\n * Fixes browser bugs in the native `String.prototype.split`. Calling `XRegExp.install('natives')`\n * uses this to override the native method. Use via `XRegExp.split` without overriding natives.\n * @private\n * @param {RegExp|String} separator Regex or string to use for separating the string.\n * @param {Number} [limit] Maximum number of items to include in the result array.\n * @returns {Array} Array of substrings.\n */\n    fixed.split = function (separator, limit) {\n        if (!self.isRegExp(separator)) {\n            return nativ.split.apply(this, arguments); // use faster native method\n        }\n        var str = String(this),\n            origLastIndex = separator.lastIndex,\n            output = [],\n            lastLastIndex = 0,\n            lastLength;\n        /* Values for `limit`, per the spec:\n         * If undefined: pow(2,32) - 1\n         * If 0, Infinity, or NaN: 0\n         * If positive number: limit = floor(limit); if (limit >= pow(2,32)) limit -= pow(2,32);\n         * If negative number: pow(2,32) - floor(abs(limit))\n         * If other: Type-convert, then use the above rules\n         */\n        limit = (limit === undef ? -1 : limit) >>> 0;\n        self.forEach(str, separator, function (match) {\n            if ((match.index + match[0].length) > lastLastIndex) { // != `if (match[0].length)`\n                output.push(str.slice(lastLastIndex, match.index));\n                if (match.length > 1 && match.index < str.length) {\n                    Array.prototype.push.apply(output, match.slice(1));\n                }\n                lastLength = match[0].length;\n                lastLastIndex = match.index + lastLength;\n            }\n        });\n        if (lastLastIndex === str.length) {\n            if (!nativ.test.call(separator, \"\") || lastLength) {\n                output.push(\"\");\n            }\n        } else {\n            output.push(str.slice(lastLastIndex));\n        }\n        separator.lastIndex = origLastIndex;\n        return output.length > limit ? output.slice(0, limit) : output;\n    };\n\n/*--------------------------------------\n *  Built-in tokens\n *------------------------------------*/\n\n// Shortcut\n    add = addToken.on;\n\n/* Letter identity escapes that natively match literal characters: \\p, \\P, etc.\n * Should be SyntaxErrors but are allowed in web reality. XRegExp makes them errors for cross-\n * browser consistency and to reserve their syntax, but lets them be superseded by XRegExp addons.\n */\n    add(/\\\\([ABCE-RTUVXYZaeg-mopqyz]|c(?![A-Za-z])|u(?![\\dA-Fa-f]{4})|x(?![\\dA-Fa-f]{2}))/,\n        function (match, scope) {\n            // \\B is allowed in default scope only\n            if (match[1] === \"B\" && scope === defaultScope) {\n                return match[0];\n            }\n            throw new SyntaxError(\"invalid escape \" + match[0]);\n        },\n        {scope: \"all\"});\n\n/* Empty character class: [] or [^]\n * Fixes a critical cross-browser syntax inconsistency. Unless this is standardized (per the spec),\n * regex syntax can't be accurately parsed because character class endings can't be determined.\n */\n    add(/\\[(\\^?)]/,\n        function (match) {\n            // For cross-browser compatibility with ES3, convert [] to \\b\\B and [^] to [\\s\\S].\n            // (?!) should work like \\b\\B, but is unreliable in Firefox\n            return match[1] ? \"[\\\\s\\\\S]\" : \"\\\\b\\\\B\";\n        });\n\n/* Comment pattern: (?# )\n * Inline comments are an alternative to the line comments allowed in free-spacing mode (flag x).\n */\n    add(/(?:\\(\\?#[^)]*\\))+/,\n        function (match) {\n            // Keep tokens separated unless the following token is a quantifier\n            return nativ.test.call(quantifier, match.input.slice(match.index + match[0].length)) ? \"\" : \"(?:)\";\n        });\n\n/* Named backreference: \\k<name>\n * Backreference names can use the characters A-Z, a-z, 0-9, _, and $ only.\n */\n    add(/\\\\k<([\\w$]+)>/,\n        function (match) {\n            var index = isNaN(match[1]) ? (lastIndexOf(this.captureNames, match[1]) + 1) : +match[1],\n                endIndex = match.index + match[0].length;\n            if (!index || index > this.captureNames.length) {\n                throw new SyntaxError(\"backreference to undefined group \" + match[0]);\n            }\n            // Keep backreferences separate from subsequent literal numbers\n            return \"\\\\\" + index + (\n                endIndex === match.input.length || isNaN(match.input.charAt(endIndex)) ? \"\" : \"(?:)\"\n            );\n        });\n\n/* Whitespace and line comments, in free-spacing mode (aka extended mode, flag x) only.\n */\n    add(/(?:\\s+|#.*)+/,\n        function (match) {\n            // Keep tokens separated unless the following token is a quantifier\n            return nativ.test.call(quantifier, match.input.slice(match.index + match[0].length)) ? \"\" : \"(?:)\";\n        },\n        {\n            trigger: function () {\n                return this.hasFlag(\"x\");\n            },\n            customFlags: \"x\"\n        });\n\n/* Dot, in dotall mode (aka singleline mode, flag s) only.\n */\n    add(/\\./,\n        function () {\n            return \"[\\\\s\\\\S]\";\n        },\n        {\n            trigger: function () {\n                return this.hasFlag(\"s\");\n            },\n            customFlags: \"s\"\n        });\n\n/* Named capturing group; match the opening delimiter only: (?<name>\n * Capture names can use the characters A-Z, a-z, 0-9, _, and $ only. Names can't be integers.\n * Supports Python-style (?P<name> as an alternate syntax to avoid issues in recent Opera (which\n * natively supports the Python-style syntax). Otherwise, XRegExp might treat numbered\n * backreferences to Python-style named capture as octals.\n */\n    add(/\\(\\?P?<([\\w$]+)>/,\n        function (match) {\n            if (!isNaN(match[1])) {\n                // Avoid incorrect lookups, since named backreferences are added to match arrays\n                throw new SyntaxError(\"can't use integer as capture name \" + match[0]);\n            }\n            this.captureNames.push(match[1]);\n            this.hasNamedCapture = true;\n            return \"(\";\n        });\n\n/* Numbered backreference or octal, plus any following digits: \\0, \\11, etc.\n * Octals except \\0 not followed by 0-9 and backreferences to unopened capture groups throw an\n * error. Other matches are returned unaltered. IE <= 8 doesn't support backreferences greater than\n * \\99 in regex syntax.\n */\n    add(/\\\\(\\d+)/,\n        function (match, scope) {\n            if (!(scope === defaultScope && /^[1-9]/.test(match[1]) && +match[1] <= this.captureNames.length) &&\n                    match[1] !== \"0\") {\n                throw new SyntaxError(\"can't use octal escape or backreference to undefined group \" + match[0]);\n            }\n            return match[0];\n        },\n        {scope: \"all\"});\n\n/* Capturing group; match the opening parenthesis only.\n * Required for support of named capturing groups. Also adds explicit capture mode (flag n).\n */\n    add(/\\((?!\\?)/,\n        function () {\n            if (this.hasFlag(\"n\")) {\n                return \"(?:\";\n            }\n            this.captureNames.push(null);\n            return \"(\";\n        },\n        {customFlags: \"n\"});\n\n/*--------------------------------------\n *  Expose XRegExp\n *------------------------------------*/\n\n// For CommonJS enviroments\n    if (typeof exports !== \"undefined\") {\n        exports.XRegExp = self;\n    }\n\n    return self;\n\n}());\n\n\n/***** unicode-base.js *****/\n\n/*!\n * XRegExp Unicode Base v1.0.0\n * (c) 2008-2012 Steven Levithan <http://xregexp.com/>\n * MIT License\n * Uses Unicode 6.1 <http://unicode.org/>\n */\n\n/**\n * Adds support for the `\\p{L}` or `\\p{Letter}` Unicode category. Addon packages for other Unicode\n * categories, scripts, blocks, and properties are available separately. All Unicode tokens can be\n * inverted using `\\P{..}` or `\\p{^..}`. Token names are case insensitive, and any spaces, hyphens,\n * and underscores are ignored.\n * @requires XRegExp\n */\n(function (XRegExp) {\n    \"use strict\";\n\n    var unicode = {};\n\n/*--------------------------------------\n *  Private helper functions\n *------------------------------------*/\n\n// Generates a standardized token name (lowercase, with hyphens, spaces, and underscores removed)\n    function slug(name) {\n        return name.replace(/[- _]+/g, \"\").toLowerCase();\n    }\n\n// Expands a list of Unicode code points and ranges to be usable in a regex character class\n    function expand(str) {\n        return str.replace(/\\w{4}/g, \"\\\\u$&\");\n    }\n\n// Adds leading zeros if shorter than four characters\n    function pad4(str) {\n        while (str.length < 4) {\n            str = \"0\" + str;\n        }\n        return str;\n    }\n\n// Converts a hexadecimal number to decimal\n    function dec(hex) {\n        return parseInt(hex, 16);\n    }\n\n// Converts a decimal number to hexadecimal\n    function hex(dec) {\n        return parseInt(dec, 10).toString(16);\n    }\n\n// Inverts a list of Unicode code points and ranges\n    function invert(range) {\n        var output = [],\n            lastEnd = -1,\n            start;\n        XRegExp.forEach(range, /\\\\u(\\w{4})(?:-\\\\u(\\w{4}))?/, function (m) {\n            start = dec(m[1]);\n            if (start > (lastEnd + 1)) {\n                output.push(\"\\\\u\" + pad4(hex(lastEnd + 1)));\n                if (start > (lastEnd + 2)) {\n                    output.push(\"-\\\\u\" + pad4(hex(start - 1)));\n                }\n            }\n            lastEnd = dec(m[2] || m[1]);\n        });\n        if (lastEnd < 0xFFFF) {\n            output.push(\"\\\\u\" + pad4(hex(lastEnd + 1)));\n            if (lastEnd < 0xFFFE) {\n                output.push(\"-\\\\uFFFF\");\n            }\n        }\n        return output.join(\"\");\n    }\n\n// Generates an inverted token on first use\n    function cacheInversion(item) {\n        return unicode[\"^\" + item] || (unicode[\"^\" + item] = invert(unicode[item]));\n    }\n\n/*--------------------------------------\n *  Core functionality\n *------------------------------------*/\n\n    XRegExp.install(\"extensibility\");\n\n/**\n * Adds to the list of Unicode properties that XRegExp regexes can match via \\p{..} or \\P{..}.\n * @memberOf XRegExp\n * @param {Object} pack Named sets of Unicode code points and ranges.\n * @param {Object} [aliases] Aliases for the primary token names.\n * @example\n *\n * XRegExp.addUnicodePackage({\n *   XDigit: '0030-00390041-00460061-0066' // 0-9A-Fa-f\n * }, {\n *   XDigit: 'Hexadecimal'\n * });\n */\n    XRegExp.addUnicodePackage = function (pack, aliases) {\n        var p;\n        if (!XRegExp.isInstalled(\"extensibility\")) {\n            throw new Error(\"extensibility must be installed before adding Unicode packages\");\n        }\n        if (pack) {\n            for (p in pack) {\n                if (pack.hasOwnProperty(p)) {\n                    unicode[slug(p)] = expand(pack[p]);\n                }\n            }\n        }\n        if (aliases) {\n            for (p in aliases) {\n                if (aliases.hasOwnProperty(p)) {\n                    unicode[slug(aliases[p])] = unicode[slug(p)];\n                }\n            }\n        }\n    };\n\n/* Adds data for the Unicode `Letter` category. Addon packages include other categories, scripts,\n * blocks, and properties.\n */\n    XRegExp.addUnicodePackage({\n        L: \"0041-005A0061-007A00AA00B500BA00C0-00D600D8-00F600F8-02C102C6-02D102E0-02E402EC02EE0370-037403760377037A-037D03860388-038A038C038E-03A103A3-03F503F7-0481048A-05270531-055605590561-058705D0-05EA05F0-05F20620-064A066E066F0671-06D306D506E506E606EE06EF06FA-06FC06FF07100712-072F074D-07A507B107CA-07EA07F407F507FA0800-0815081A082408280840-085808A008A2-08AC0904-0939093D09500958-09610971-09770979-097F0985-098C098F09900993-09A809AA-09B009B209B6-09B909BD09CE09DC09DD09DF-09E109F009F10A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A59-0A5C0A5E0A72-0A740A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABD0AD00AE00AE10B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3D0B5C0B5D0B5F-0B610B710B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BD00C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D0C580C590C600C610C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBD0CDE0CE00CE10CF10CF20D05-0D0C0D0E-0D100D12-0D3A0D3D0D4E0D600D610D7A-0D7F0D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60E01-0E300E320E330E40-0E460E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB00EB20EB30EBD0EC0-0EC40EC60EDC-0EDF0F000F40-0F470F49-0F6C0F88-0F8C1000-102A103F1050-1055105A-105D106110651066106E-10701075-1081108E10A0-10C510C710CD10D0-10FA10FC-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A1380-138F13A0-13F41401-166C166F-167F1681-169A16A0-16EA1700-170C170E-17111720-17311740-17511760-176C176E-17701780-17B317D717DC1820-18771880-18A818AA18B0-18F51900-191C1950-196D1970-19741980-19AB19C1-19C71A00-1A161A20-1A541AA71B05-1B331B45-1B4B1B83-1BA01BAE1BAF1BBA-1BE51C00-1C231C4D-1C4F1C5A-1C7D1CE9-1CEC1CEE-1CF11CF51CF61D00-1DBF1E00-1F151F18-1F1D1F20-1F451F48-1F4D1F50-1F571F591F5B1F5D1F5F-1F7D1F80-1FB41FB6-1FBC1FBE1FC2-1FC41FC6-1FCC1FD0-1FD31FD6-1FDB1FE0-1FEC1FF2-1FF41FF6-1FFC2071207F2090-209C21022107210A-211321152119-211D212421262128212A-212D212F-2139213C-213F2145-2149214E218321842C00-2C2E2C30-2C5E2C60-2CE42CEB-2CEE2CF22CF32D00-2D252D272D2D2D30-2D672D6F2D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE2E2F300530063031-3035303B303C3041-3096309D-309F30A1-30FA30FC-30FF3105-312D3131-318E31A0-31BA31F0-31FF3400-4DB54E00-9FCCA000-A48CA4D0-A4FDA500-A60CA610-A61FA62AA62BA640-A66EA67F-A697A6A0-A6E5A717-A71FA722-A788A78B-A78EA790-A793A7A0-A7AAA7F8-A801A803-A805A807-A80AA80C-A822A840-A873A882-A8B3A8F2-A8F7A8FBA90A-A925A930-A946A960-A97CA984-A9B2A9CFAA00-AA28AA40-AA42AA44-AA4BAA60-AA76AA7AAA80-AAAFAAB1AAB5AAB6AAB9-AABDAAC0AAC2AADB-AADDAAE0-AAEAAAF2-AAF4AB01-AB06AB09-AB0EAB11-AB16AB20-AB26AB28-AB2EABC0-ABE2AC00-D7A3D7B0-D7C6D7CB-D7FBF900-FA6DFA70-FAD9FB00-FB06FB13-FB17FB1DFB1F-FB28FB2A-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBB1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFBFE70-FE74FE76-FEFCFF21-FF3AFF41-FF5AFF66-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC\"\n    }, {\n        L: \"Letter\"\n    });\n\n/* Adds Unicode property syntax to XRegExp: \\p{..}, \\P{..}, \\p{^..}\n */\n    XRegExp.addToken(\n        /\\\\([pP]){(\\^?)([^}]*)}/,\n        function (match, scope) {\n            var inv = (match[1] === \"P\" || match[2]) ? \"^\" : \"\",\n                item = slug(match[3]);\n            // The double negative \\P{^..} is invalid\n            if (match[1] === \"P\" && match[2]) {\n                throw new SyntaxError(\"invalid double negation \\\\P{^\");\n            }\n            if (!unicode.hasOwnProperty(item)) {\n                throw new SyntaxError(\"invalid or unknown Unicode property \" + match[0]);\n            }\n            return scope === \"class\" ?\n                    (inv ? cacheInversion(item) : unicode[item]) :\n                    \"[\" + inv + unicode[item] + \"]\";\n        },\n        {scope: \"all\"}\n    );\n\n}(XRegExp));\n\n\n/***** unicode-categories.js *****/\n\n/*!\n * XRegExp Unicode Categories v1.2.0\n * (c) 2010-2012 Steven Levithan <http://xregexp.com/>\n * MIT License\n * Uses Unicode 6.1 <http://unicode.org/>\n */\n\n/**\n * Adds support for all Unicode categories (aka properties) E.g., `\\p{Lu}` or\n * `\\p{Uppercase Letter}`. Token names are case insensitive, and any spaces, hyphens, and\n * underscores are ignored.\n * @requires XRegExp, XRegExp Unicode Base\n */\n(function (XRegExp) {\n    \"use strict\";\n\n    if (!XRegExp.addUnicodePackage) {\n        throw new ReferenceError(\"Unicode Base must be loaded before Unicode Categories\");\n    }\n\n    XRegExp.install(\"extensibility\");\n\n    XRegExp.addUnicodePackage({\n        //L: \"\", // Included in the Unicode Base addon\n        Ll: \"0061-007A00B500DF-00F600F8-00FF01010103010501070109010B010D010F01110113011501170119011B011D011F01210123012501270129012B012D012F01310133013501370138013A013C013E014001420144014601480149014B014D014F01510153015501570159015B015D015F01610163016501670169016B016D016F0171017301750177017A017C017E-0180018301850188018C018D019201950199-019B019E01A101A301A501A801AA01AB01AD01B001B401B601B901BA01BD-01BF01C601C901CC01CE01D001D201D401D601D801DA01DC01DD01DF01E101E301E501E701E901EB01ED01EF01F001F301F501F901FB01FD01FF02010203020502070209020B020D020F02110213021502170219021B021D021F02210223022502270229022B022D022F02310233-0239023C023F0240024202470249024B024D024F-02930295-02AF037103730377037B-037D039003AC-03CE03D003D103D5-03D703D903DB03DD03DF03E103E303E503E703E903EB03ED03EF-03F303F503F803FB03FC0430-045F04610463046504670469046B046D046F04710473047504770479047B047D047F0481048B048D048F04910493049504970499049B049D049F04A104A304A504A704A904AB04AD04AF04B104B304B504B704B904BB04BD04BF04C204C404C604C804CA04CC04CE04CF04D104D304D504D704D904DB04DD04DF04E104E304E504E704E904EB04ED04EF04F104F304F504F704F904FB04FD04FF05010503050505070509050B050D050F05110513051505170519051B051D051F05210523052505270561-05871D00-1D2B1D6B-1D771D79-1D9A1E011E031E051E071E091E0B1E0D1E0F1E111E131E151E171E191E1B1E1D1E1F1E211E231E251E271E291E2B1E2D1E2F1E311E331E351E371E391E3B1E3D1E3F1E411E431E451E471E491E4B1E4D1E4F1E511E531E551E571E591E5B1E5D1E5F1E611E631E651E671E691E6B1E6D1E6F1E711E731E751E771E791E7B1E7D1E7F1E811E831E851E871E891E8B1E8D1E8F1E911E931E95-1E9D1E9F1EA11EA31EA51EA71EA91EAB1EAD1EAF1EB11EB31EB51EB71EB91EBB1EBD1EBF1EC11EC31EC51EC71EC91ECB1ECD1ECF1ED11ED31ED51ED71ED91EDB1EDD1EDF1EE11EE31EE51EE71EE91EEB1EED1EEF1EF11EF31EF51EF71EF91EFB1EFD1EFF-1F071F10-1F151F20-1F271F30-1F371F40-1F451F50-1F571F60-1F671F70-1F7D1F80-1F871F90-1F971FA0-1FA71FB0-1FB41FB61FB71FBE1FC2-1FC41FC61FC71FD0-1FD31FD61FD71FE0-1FE71FF2-1FF41FF61FF7210A210E210F2113212F21342139213C213D2146-2149214E21842C30-2C5E2C612C652C662C682C6A2C6C2C712C732C742C76-2C7B2C812C832C852C872C892C8B2C8D2C8F2C912C932C952C972C992C9B2C9D2C9F2CA12CA32CA52CA72CA92CAB2CAD2CAF2CB12CB32CB52CB72CB92CBB2CBD2CBF2CC12CC32CC52CC72CC92CCB2CCD2CCF2CD12CD32CD52CD72CD92CDB2CDD2CDF2CE12CE32CE42CEC2CEE2CF32D00-2D252D272D2DA641A643A645A647A649A64BA64DA64FA651A653A655A657A659A65BA65DA65FA661A663A665A667A669A66BA66DA681A683A685A687A689A68BA68DA68FA691A693A695A697A723A725A727A729A72BA72DA72F-A731A733A735A737A739A73BA73DA73FA741A743A745A747A749A74BA74DA74FA751A753A755A757A759A75BA75DA75FA761A763A765A767A769A76BA76DA76FA771-A778A77AA77CA77FA781A783A785A787A78CA78EA791A793A7A1A7A3A7A5A7A7A7A9A7FAFB00-FB06FB13-FB17FF41-FF5A\",\n        Lu: \"0041-005A00C0-00D600D8-00DE01000102010401060108010A010C010E01100112011401160118011A011C011E01200122012401260128012A012C012E01300132013401360139013B013D013F0141014301450147014A014C014E01500152015401560158015A015C015E01600162016401660168016A016C016E017001720174017601780179017B017D018101820184018601870189-018B018E-0191019301940196-0198019C019D019F01A001A201A401A601A701A901AC01AE01AF01B1-01B301B501B701B801BC01C401C701CA01CD01CF01D101D301D501D701D901DB01DE01E001E201E401E601E801EA01EC01EE01F101F401F6-01F801FA01FC01FE02000202020402060208020A020C020E02100212021402160218021A021C021E02200222022402260228022A022C022E02300232023A023B023D023E02410243-02460248024A024C024E03700372037603860388-038A038C038E038F0391-03A103A3-03AB03CF03D2-03D403D803DA03DC03DE03E003E203E403E603E803EA03EC03EE03F403F703F903FA03FD-042F04600462046404660468046A046C046E04700472047404760478047A047C047E0480048A048C048E04900492049404960498049A049C049E04A004A204A404A604A804AA04AC04AE04B004B204B404B604B804BA04BC04BE04C004C104C304C504C704C904CB04CD04D004D204D404D604D804DA04DC04DE04E004E204E404E604E804EA04EC04EE04F004F204F404F604F804FA04FC04FE05000502050405060508050A050C050E05100512051405160518051A051C051E05200522052405260531-055610A0-10C510C710CD1E001E021E041E061E081E0A1E0C1E0E1E101E121E141E161E181E1A1E1C1E1E1E201E221E241E261E281E2A1E2C1E2E1E301E321E341E361E381E3A1E3C1E3E1E401E421E441E461E481E4A1E4C1E4E1E501E521E541E561E581E5A1E5C1E5E1E601E621E641E661E681E6A1E6C1E6E1E701E721E741E761E781E7A1E7C1E7E1E801E821E841E861E881E8A1E8C1E8E1E901E921E941E9E1EA01EA21EA41EA61EA81EAA1EAC1EAE1EB01EB21EB41EB61EB81EBA1EBC1EBE1EC01EC21EC41EC61EC81ECA1ECC1ECE1ED01ED21ED41ED61ED81EDA1EDC1EDE1EE01EE21EE41EE61EE81EEA1EEC1EEE1EF01EF21EF41EF61EF81EFA1EFC1EFE1F08-1F0F1F18-1F1D1F28-1F2F1F38-1F3F1F48-1F4D1F591F5B1F5D1F5F1F68-1F6F1FB8-1FBB1FC8-1FCB1FD8-1FDB1FE8-1FEC1FF8-1FFB21022107210B-210D2110-211221152119-211D212421262128212A-212D2130-2133213E213F214521832C00-2C2E2C602C62-2C642C672C692C6B2C6D-2C702C722C752C7E-2C802C822C842C862C882C8A2C8C2C8E2C902C922C942C962C982C9A2C9C2C9E2CA02CA22CA42CA62CA82CAA2CAC2CAE2CB02CB22CB42CB62CB82CBA2CBC2CBE2CC02CC22CC42CC62CC82CCA2CCC2CCE2CD02CD22CD42CD62CD82CDA2CDC2CDE2CE02CE22CEB2CED2CF2A640A642A644A646A648A64AA64CA64EA650A652A654A656A658A65AA65CA65EA660A662A664A666A668A66AA66CA680A682A684A686A688A68AA68CA68EA690A692A694A696A722A724A726A728A72AA72CA72EA732A734A736A738A73AA73CA73EA740A742A744A746A748A74AA74CA74EA750A752A754A756A758A75AA75CA75EA760A762A764A766A768A76AA76CA76EA779A77BA77DA77EA780A782A784A786A78BA78DA790A792A7A0A7A2A7A4A7A6A7A8A7AAFF21-FF3A\",\n        Lt: \"01C501C801CB01F21F88-1F8F1F98-1F9F1FA8-1FAF1FBC1FCC1FFC\",\n        Lm: \"02B0-02C102C6-02D102E0-02E402EC02EE0374037A0559064006E506E607F407F507FA081A0824082809710E460EC610FC17D718431AA71C78-1C7D1D2C-1D6A1D781D9B-1DBF2071207F2090-209C2C7C2C7D2D6F2E2F30053031-3035303B309D309E30FC-30FEA015A4F8-A4FDA60CA67FA717-A71FA770A788A7F8A7F9A9CFAA70AADDAAF3AAF4FF70FF9EFF9F\",\n        Lo: \"00AA00BA01BB01C0-01C3029405D0-05EA05F0-05F20620-063F0641-064A066E066F0671-06D306D506EE06EF06FA-06FC06FF07100712-072F074D-07A507B107CA-07EA0800-08150840-085808A008A2-08AC0904-0939093D09500958-09610972-09770979-097F0985-098C098F09900993-09A809AA-09B009B209B6-09B909BD09CE09DC09DD09DF-09E109F009F10A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A59-0A5C0A5E0A72-0A740A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABD0AD00AE00AE10B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3D0B5C0B5D0B5F-0B610B710B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BD00C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D0C580C590C600C610C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBD0CDE0CE00CE10CF10CF20D05-0D0C0D0E-0D100D12-0D3A0D3D0D4E0D600D610D7A-0D7F0D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60E01-0E300E320E330E40-0E450E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB00EB20EB30EBD0EC0-0EC40EDC-0EDF0F000F40-0F470F49-0F6C0F88-0F8C1000-102A103F1050-1055105A-105D106110651066106E-10701075-1081108E10D0-10FA10FD-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A1380-138F13A0-13F41401-166C166F-167F1681-169A16A0-16EA1700-170C170E-17111720-17311740-17511760-176C176E-17701780-17B317DC1820-18421844-18771880-18A818AA18B0-18F51900-191C1950-196D1970-19741980-19AB19C1-19C71A00-1A161A20-1A541B05-1B331B45-1B4B1B83-1BA01BAE1BAF1BBA-1BE51C00-1C231C4D-1C4F1C5A-1C771CE9-1CEC1CEE-1CF11CF51CF62135-21382D30-2D672D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE3006303C3041-3096309F30A1-30FA30FF3105-312D3131-318E31A0-31BA31F0-31FF3400-4DB54E00-9FCCA000-A014A016-A48CA4D0-A4F7A500-A60BA610-A61FA62AA62BA66EA6A0-A6E5A7FB-A801A803-A805A807-A80AA80C-A822A840-A873A882-A8B3A8F2-A8F7A8FBA90A-A925A930-A946A960-A97CA984-A9B2AA00-AA28AA40-AA42AA44-AA4BAA60-AA6FAA71-AA76AA7AAA80-AAAFAAB1AAB5AAB6AAB9-AABDAAC0AAC2AADBAADCAAE0-AAEAAAF2AB01-AB06AB09-AB0EAB11-AB16AB20-AB26AB28-AB2EABC0-ABE2AC00-D7A3D7B0-D7C6D7CB-D7FBF900-FA6DFA70-FAD9FB1DFB1F-FB28FB2A-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBB1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFBFE70-FE74FE76-FEFCFF66-FF6FFF71-FF9DFFA0-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC\",\n        M: \"0300-036F0483-04890591-05BD05BF05C105C205C405C505C70610-061A064B-065F067006D6-06DC06DF-06E406E706E806EA-06ED07110730-074A07A6-07B007EB-07F30816-0819081B-08230825-08270829-082D0859-085B08E4-08FE0900-0903093A-093C093E-094F0951-0957096209630981-098309BC09BE-09C409C709C809CB-09CD09D709E209E30A01-0A030A3C0A3E-0A420A470A480A4B-0A4D0A510A700A710A750A81-0A830ABC0ABE-0AC50AC7-0AC90ACB-0ACD0AE20AE30B01-0B030B3C0B3E-0B440B470B480B4B-0B4D0B560B570B620B630B820BBE-0BC20BC6-0BC80BCA-0BCD0BD70C01-0C030C3E-0C440C46-0C480C4A-0C4D0C550C560C620C630C820C830CBC0CBE-0CC40CC6-0CC80CCA-0CCD0CD50CD60CE20CE30D020D030D3E-0D440D46-0D480D4A-0D4D0D570D620D630D820D830DCA0DCF-0DD40DD60DD8-0DDF0DF20DF30E310E34-0E3A0E47-0E4E0EB10EB4-0EB90EBB0EBC0EC8-0ECD0F180F190F350F370F390F3E0F3F0F71-0F840F860F870F8D-0F970F99-0FBC0FC6102B-103E1056-1059105E-10601062-10641067-106D1071-10741082-108D108F109A-109D135D-135F1712-17141732-1734175217531772177317B4-17D317DD180B-180D18A91920-192B1930-193B19B0-19C019C819C91A17-1A1B1A55-1A5E1A60-1A7C1A7F1B00-1B041B34-1B441B6B-1B731B80-1B821BA1-1BAD1BE6-1BF31C24-1C371CD0-1CD21CD4-1CE81CED1CF2-1CF41DC0-1DE61DFC-1DFF20D0-20F02CEF-2CF12D7F2DE0-2DFF302A-302F3099309AA66F-A672A674-A67DA69FA6F0A6F1A802A806A80BA823-A827A880A881A8B4-A8C4A8E0-A8F1A926-A92DA947-A953A980-A983A9B3-A9C0AA29-AA36AA43AA4CAA4DAA7BAAB0AAB2-AAB4AAB7AAB8AABEAABFAAC1AAEB-AAEFAAF5AAF6ABE3-ABEAABECABEDFB1EFE00-FE0FFE20-FE26\",\n        Mn: \"0300-036F0483-04870591-05BD05BF05C105C205C405C505C70610-061A064B-065F067006D6-06DC06DF-06E406E706E806EA-06ED07110730-074A07A6-07B007EB-07F30816-0819081B-08230825-08270829-082D0859-085B08E4-08FE0900-0902093A093C0941-0948094D0951-095709620963098109BC09C1-09C409CD09E209E30A010A020A3C0A410A420A470A480A4B-0A4D0A510A700A710A750A810A820ABC0AC1-0AC50AC70AC80ACD0AE20AE30B010B3C0B3F0B41-0B440B4D0B560B620B630B820BC00BCD0C3E-0C400C46-0C480C4A-0C4D0C550C560C620C630CBC0CBF0CC60CCC0CCD0CE20CE30D41-0D440D4D0D620D630DCA0DD2-0DD40DD60E310E34-0E3A0E47-0E4E0EB10EB4-0EB90EBB0EBC0EC8-0ECD0F180F190F350F370F390F71-0F7E0F80-0F840F860F870F8D-0F970F99-0FBC0FC6102D-10301032-10371039103A103D103E10581059105E-10601071-1074108210851086108D109D135D-135F1712-17141732-1734175217531772177317B417B517B7-17BD17C617C9-17D317DD180B-180D18A91920-19221927192819321939-193B1A171A181A561A58-1A5E1A601A621A65-1A6C1A73-1A7C1A7F1B00-1B031B341B36-1B3A1B3C1B421B6B-1B731B801B811BA2-1BA51BA81BA91BAB1BE61BE81BE91BED1BEF-1BF11C2C-1C331C361C371CD0-1CD21CD4-1CE01CE2-1CE81CED1CF41DC0-1DE61DFC-1DFF20D0-20DC20E120E5-20F02CEF-2CF12D7F2DE0-2DFF302A-302D3099309AA66FA674-A67DA69FA6F0A6F1A802A806A80BA825A826A8C4A8E0-A8F1A926-A92DA947-A951A980-A982A9B3A9B6-A9B9A9BCAA29-AA2EAA31AA32AA35AA36AA43AA4CAAB0AAB2-AAB4AAB7AAB8AABEAABFAAC1AAECAAEDAAF6ABE5ABE8ABEDFB1EFE00-FE0FFE20-FE26\",\n        Mc: \"0903093B093E-09400949-094C094E094F0982098309BE-09C009C709C809CB09CC09D70A030A3E-0A400A830ABE-0AC00AC90ACB0ACC0B020B030B3E0B400B470B480B4B0B4C0B570BBE0BBF0BC10BC20BC6-0BC80BCA-0BCC0BD70C01-0C030C41-0C440C820C830CBE0CC0-0CC40CC70CC80CCA0CCB0CD50CD60D020D030D3E-0D400D46-0D480D4A-0D4C0D570D820D830DCF-0DD10DD8-0DDF0DF20DF30F3E0F3F0F7F102B102C10311038103B103C105610571062-10641067-106D108310841087-108C108F109A-109C17B617BE-17C517C717C81923-19261929-192B193019311933-193819B0-19C019C819C91A19-1A1B1A551A571A611A631A641A6D-1A721B041B351B3B1B3D-1B411B431B441B821BA11BA61BA71BAA1BAC1BAD1BE71BEA-1BEC1BEE1BF21BF31C24-1C2B1C341C351CE11CF21CF3302E302FA823A824A827A880A881A8B4-A8C3A952A953A983A9B4A9B5A9BAA9BBA9BD-A9C0AA2FAA30AA33AA34AA4DAA7BAAEBAAEEAAEFAAF5ABE3ABE4ABE6ABE7ABE9ABEAABEC\",\n        Me: \"0488048920DD-20E020E2-20E4A670-A672\",\n        N: \"0030-003900B200B300B900BC-00BE0660-066906F0-06F907C0-07C90966-096F09E6-09EF09F4-09F90A66-0A6F0AE6-0AEF0B66-0B6F0B72-0B770BE6-0BF20C66-0C6F0C78-0C7E0CE6-0CEF0D66-0D750E50-0E590ED0-0ED90F20-0F331040-10491090-10991369-137C16EE-16F017E0-17E917F0-17F91810-18191946-194F19D0-19DA1A80-1A891A90-1A991B50-1B591BB0-1BB91C40-1C491C50-1C5920702074-20792080-20892150-21822185-21892460-249B24EA-24FF2776-27932CFD30073021-30293038-303A3192-31953220-32293248-324F3251-325F3280-328932B1-32BFA620-A629A6E6-A6EFA830-A835A8D0-A8D9A900-A909A9D0-A9D9AA50-AA59ABF0-ABF9FF10-FF19\",\n        Nd: \"0030-00390660-066906F0-06F907C0-07C90966-096F09E6-09EF0A66-0A6F0AE6-0AEF0B66-0B6F0BE6-0BEF0C66-0C6F0CE6-0CEF0D66-0D6F0E50-0E590ED0-0ED90F20-0F291040-10491090-109917E0-17E91810-18191946-194F19D0-19D91A80-1A891A90-1A991B50-1B591BB0-1BB91C40-1C491C50-1C59A620-A629A8D0-A8D9A900-A909A9D0-A9D9AA50-AA59ABF0-ABF9FF10-FF19\",\n        Nl: \"16EE-16F02160-21822185-218830073021-30293038-303AA6E6-A6EF\",\n        No: \"00B200B300B900BC-00BE09F4-09F90B72-0B770BF0-0BF20C78-0C7E0D70-0D750F2A-0F331369-137C17F0-17F919DA20702074-20792080-20892150-215F21892460-249B24EA-24FF2776-27932CFD3192-31953220-32293248-324F3251-325F3280-328932B1-32BFA830-A835\",\n        P: \"0021-00230025-002A002C-002F003A003B003F0040005B-005D005F007B007D00A100A700AB00B600B700BB00BF037E0387055A-055F0589058A05BE05C005C305C605F305F40609060A060C060D061B061E061F066A-066D06D40700-070D07F7-07F90830-083E085E0964096509700AF00DF40E4F0E5A0E5B0F04-0F120F140F3A-0F3D0F850FD0-0FD40FD90FDA104A-104F10FB1360-13681400166D166E169B169C16EB-16ED1735173617D4-17D617D8-17DA1800-180A194419451A1E1A1F1AA0-1AA61AA8-1AAD1B5A-1B601BFC-1BFF1C3B-1C3F1C7E1C7F1CC0-1CC71CD32010-20272030-20432045-20512053-205E207D207E208D208E2329232A2768-277527C527C627E6-27EF2983-299829D8-29DB29FC29FD2CF9-2CFC2CFE2CFF2D702E00-2E2E2E30-2E3B3001-30033008-30113014-301F3030303D30A030FBA4FEA4FFA60D-A60FA673A67EA6F2-A6F7A874-A877A8CEA8CFA8F8-A8FAA92EA92FA95FA9C1-A9CDA9DEA9DFAA5C-AA5FAADEAADFAAF0AAF1ABEBFD3EFD3FFE10-FE19FE30-FE52FE54-FE61FE63FE68FE6AFE6BFF01-FF03FF05-FF0AFF0C-FF0FFF1AFF1BFF1FFF20FF3B-FF3DFF3FFF5BFF5DFF5F-FF65\",\n        Pd: \"002D058A05BE140018062010-20152E172E1A2E3A2E3B301C303030A0FE31FE32FE58FE63FF0D\",\n        Ps: \"0028005B007B0F3A0F3C169B201A201E2045207D208D23292768276A276C276E27702772277427C527E627E827EA27EC27EE2983298529872989298B298D298F299129932995299729D829DA29FC2E222E242E262E283008300A300C300E3010301430163018301A301DFD3EFE17FE35FE37FE39FE3BFE3DFE3FFE41FE43FE47FE59FE5BFE5DFF08FF3BFF5BFF5FFF62\",\n        Pe: \"0029005D007D0F3B0F3D169C2046207E208E232A2769276B276D276F27712773277527C627E727E927EB27ED27EF298429862988298A298C298E2990299229942996299829D929DB29FD2E232E252E272E293009300B300D300F3011301530173019301B301E301FFD3FFE18FE36FE38FE3AFE3CFE3EFE40FE42FE44FE48FE5AFE5CFE5EFF09FF3DFF5DFF60FF63\",\n        Pi: \"00AB2018201B201C201F20392E022E042E092E0C2E1C2E20\",\n        Pf: \"00BB2019201D203A2E032E052E0A2E0D2E1D2E21\",\n        Pc: \"005F203F20402054FE33FE34FE4D-FE4FFF3F\",\n        Po: \"0021-00230025-0027002A002C002E002F003A003B003F0040005C00A100A700B600B700BF037E0387055A-055F058905C005C305C605F305F40609060A060C060D061B061E061F066A-066D06D40700-070D07F7-07F90830-083E085E0964096509700AF00DF40E4F0E5A0E5B0F04-0F120F140F850FD0-0FD40FD90FDA104A-104F10FB1360-1368166D166E16EB-16ED1735173617D4-17D617D8-17DA1800-18051807-180A194419451A1E1A1F1AA0-1AA61AA8-1AAD1B5A-1B601BFC-1BFF1C3B-1C3F1C7E1C7F1CC0-1CC71CD3201620172020-20272030-2038203B-203E2041-20432047-205120532055-205E2CF9-2CFC2CFE2CFF2D702E002E012E06-2E082E0B2E0E-2E162E182E192E1B2E1E2E1F2E2A-2E2E2E30-2E393001-3003303D30FBA4FEA4FFA60D-A60FA673A67EA6F2-A6F7A874-A877A8CEA8CFA8F8-A8FAA92EA92FA95FA9C1-A9CDA9DEA9DFAA5C-AA5FAADEAADFAAF0AAF1ABEBFE10-FE16FE19FE30FE45FE46FE49-FE4CFE50-FE52FE54-FE57FE5F-FE61FE68FE6AFE6BFF01-FF03FF05-FF07FF0AFF0CFF0EFF0FFF1AFF1BFF1FFF20FF3CFF61FF64FF65\",\n        S: \"0024002B003C-003E005E0060007C007E00A2-00A600A800A900AC00AE-00B100B400B800D700F702C2-02C502D2-02DF02E5-02EB02ED02EF-02FF03750384038503F60482058F0606-0608060B060E060F06DE06E906FD06FE07F609F209F309FA09FB0AF10B700BF3-0BFA0C7F0D790E3F0F01-0F030F130F15-0F170F1A-0F1F0F340F360F380FBE-0FC50FC7-0FCC0FCE0FCF0FD5-0FD8109E109F1390-139917DB194019DE-19FF1B61-1B6A1B74-1B7C1FBD1FBF-1FC11FCD-1FCF1FDD-1FDF1FED-1FEF1FFD1FFE20442052207A-207C208A-208C20A0-20B9210021012103-21062108210921142116-2118211E-2123212521272129212E213A213B2140-2144214A-214D214F2190-2328232B-23F32400-24262440-244A249C-24E92500-26FF2701-27672794-27C427C7-27E527F0-29822999-29D729DC-29FB29FE-2B4C2B50-2B592CE5-2CEA2E80-2E992E9B-2EF32F00-2FD52FF0-2FFB300430123013302030363037303E303F309B309C319031913196-319F31C0-31E33200-321E322A-324732503260-327F328A-32B032C0-32FE3300-33FF4DC0-4DFFA490-A4C6A700-A716A720A721A789A78AA828-A82BA836-A839AA77-AA79FB29FBB2-FBC1FDFCFDFDFE62FE64-FE66FE69FF04FF0BFF1C-FF1EFF3EFF40FF5CFF5EFFE0-FFE6FFE8-FFEEFFFCFFFD\",\n        Sm: \"002B003C-003E007C007E00AC00B100D700F703F60606-060820442052207A-207C208A-208C21182140-2144214B2190-2194219A219B21A021A321A621AE21CE21CF21D221D421F4-22FF2308-230B23202321237C239B-23B323DC-23E125B725C125F8-25FF266F27C0-27C427C7-27E527F0-27FF2900-29822999-29D729DC-29FB29FE-2AFF2B30-2B442B47-2B4CFB29FE62FE64-FE66FF0BFF1C-FF1EFF5CFF5EFFE2FFE9-FFEC\",\n        Sc: \"002400A2-00A5058F060B09F209F309FB0AF10BF90E3F17DB20A0-20B9A838FDFCFE69FF04FFE0FFE1FFE5FFE6\",\n        Sk: \"005E006000A800AF00B400B802C2-02C502D2-02DF02E5-02EB02ED02EF-02FF0375038403851FBD1FBF-1FC11FCD-1FCF1FDD-1FDF1FED-1FEF1FFD1FFE309B309CA700-A716A720A721A789A78AFBB2-FBC1FF3EFF40FFE3\",\n        So: \"00A600A900AE00B00482060E060F06DE06E906FD06FE07F609FA0B700BF3-0BF80BFA0C7F0D790F01-0F030F130F15-0F170F1A-0F1F0F340F360F380FBE-0FC50FC7-0FCC0FCE0FCF0FD5-0FD8109E109F1390-1399194019DE-19FF1B61-1B6A1B74-1B7C210021012103-210621082109211421162117211E-2123212521272129212E213A213B214A214C214D214F2195-2199219C-219F21A121A221A421A521A7-21AD21AF-21CD21D021D121D321D5-21F32300-2307230C-231F2322-2328232B-237B237D-239A23B4-23DB23E2-23F32400-24262440-244A249C-24E92500-25B625B8-25C025C2-25F72600-266E2670-26FF2701-27672794-27BF2800-28FF2B00-2B2F2B452B462B50-2B592CE5-2CEA2E80-2E992E9B-2EF32F00-2FD52FF0-2FFB300430123013302030363037303E303F319031913196-319F31C0-31E33200-321E322A-324732503260-327F328A-32B032C0-32FE3300-33FF4DC0-4DFFA490-A4C6A828-A82BA836A837A839AA77-AA79FDFDFFE4FFE8FFEDFFEEFFFCFFFD\",\n        Z: \"002000A01680180E2000-200A20282029202F205F3000\",\n        Zs: \"002000A01680180E2000-200A202F205F3000\",\n        Zl: \"2028\",\n        Zp: \"2029\",\n        C: \"0000-001F007F-009F00AD03780379037F-0383038B038D03A20528-05300557055805600588058B-058E059005C8-05CF05EB-05EF05F5-0605061C061D06DD070E070F074B074C07B2-07BF07FB-07FF082E082F083F085C085D085F-089F08A108AD-08E308FF097809800984098D098E0991099209A909B109B3-09B509BA09BB09C509C609C909CA09CF-09D609D8-09DB09DE09E409E509FC-0A000A040A0B-0A0E0A110A120A290A310A340A370A3A0A3B0A3D0A43-0A460A490A4A0A4E-0A500A52-0A580A5D0A5F-0A650A76-0A800A840A8E0A920AA90AB10AB40ABA0ABB0AC60ACA0ACE0ACF0AD1-0ADF0AE40AE50AF2-0B000B040B0D0B0E0B110B120B290B310B340B3A0B3B0B450B460B490B4A0B4E-0B550B58-0B5B0B5E0B640B650B78-0B810B840B8B-0B8D0B910B96-0B980B9B0B9D0BA0-0BA20BA5-0BA70BAB-0BAD0BBA-0BBD0BC3-0BC50BC90BCE0BCF0BD1-0BD60BD8-0BE50BFB-0C000C040C0D0C110C290C340C3A-0C3C0C450C490C4E-0C540C570C5A-0C5F0C640C650C70-0C770C800C810C840C8D0C910CA90CB40CBA0CBB0CC50CC90CCE-0CD40CD7-0CDD0CDF0CE40CE50CF00CF3-0D010D040D0D0D110D3B0D3C0D450D490D4F-0D560D58-0D5F0D640D650D76-0D780D800D810D840D97-0D990DB20DBC0DBE0DBF0DC7-0DC90DCB-0DCE0DD50DD70DE0-0DF10DF5-0E000E3B-0E3E0E5C-0E800E830E850E860E890E8B0E8C0E8E-0E930E980EA00EA40EA60EA80EA90EAC0EBA0EBE0EBF0EC50EC70ECE0ECF0EDA0EDB0EE0-0EFF0F480F6D-0F700F980FBD0FCD0FDB-0FFF10C610C8-10CC10CE10CF1249124E124F12571259125E125F1289128E128F12B112B612B712BF12C112C612C712D7131113161317135B135C137D-137F139A-139F13F5-13FF169D-169F16F1-16FF170D1715-171F1737-173F1754-175F176D17711774-177F17DE17DF17EA-17EF17FA-17FF180F181A-181F1878-187F18AB-18AF18F6-18FF191D-191F192C-192F193C-193F1941-1943196E196F1975-197F19AC-19AF19CA-19CF19DB-19DD1A1C1A1D1A5F1A7D1A7E1A8A-1A8F1A9A-1A9F1AAE-1AFF1B4C-1B4F1B7D-1B7F1BF4-1BFB1C38-1C3A1C4A-1C4C1C80-1CBF1CC8-1CCF1CF7-1CFF1DE7-1DFB1F161F171F1E1F1F1F461F471F4E1F4F1F581F5A1F5C1F5E1F7E1F7F1FB51FC51FD41FD51FDC1FF01FF11FF51FFF200B-200F202A-202E2060-206F20722073208F209D-209F20BA-20CF20F1-20FF218A-218F23F4-23FF2427-243F244B-245F27002B4D-2B4F2B5A-2BFF2C2F2C5F2CF4-2CF82D262D28-2D2C2D2E2D2F2D68-2D6E2D71-2D7E2D97-2D9F2DA72DAF2DB72DBF2DC72DCF2DD72DDF2E3C-2E7F2E9A2EF4-2EFF2FD6-2FEF2FFC-2FFF3040309730983100-3104312E-3130318F31BB-31BF31E4-31EF321F32FF4DB6-4DBF9FCD-9FFFA48D-A48FA4C7-A4CFA62C-A63FA698-A69EA6F8-A6FFA78FA794-A79FA7AB-A7F7A82C-A82FA83A-A83FA878-A87FA8C5-A8CDA8DA-A8DFA8FC-A8FFA954-A95EA97D-A97FA9CEA9DA-A9DDA9E0-A9FFAA37-AA3FAA4EAA4FAA5AAA5BAA7C-AA7FAAC3-AADAAAF7-AB00AB07AB08AB0FAB10AB17-AB1FAB27AB2F-ABBFABEEABEFABFA-ABFFD7A4-D7AFD7C7-D7CAD7FC-F8FFFA6EFA6FFADA-FAFFFB07-FB12FB18-FB1CFB37FB3DFB3FFB42FB45FBC2-FBD2FD40-FD4FFD90FD91FDC8-FDEFFDFEFDFFFE1A-FE1FFE27-FE2FFE53FE67FE6C-FE6FFE75FEFD-FF00FFBF-FFC1FFC8FFC9FFD0FFD1FFD8FFD9FFDD-FFDFFFE7FFEF-FFFBFFFEFFFF\",\n        Cc: \"0000-001F007F-009F\",\n        Cf: \"00AD0600-060406DD070F200B-200F202A-202E2060-2064206A-206FFEFFFFF9-FFFB\",\n        Co: \"E000-F8FF\",\n        Cs: \"D800-DFFF\",\n        Cn: \"03780379037F-0383038B038D03A20528-05300557055805600588058B-058E059005C8-05CF05EB-05EF05F5-05FF0605061C061D070E074B074C07B2-07BF07FB-07FF082E082F083F085C085D085F-089F08A108AD-08E308FF097809800984098D098E0991099209A909B109B3-09B509BA09BB09C509C609C909CA09CF-09D609D8-09DB09DE09E409E509FC-0A000A040A0B-0A0E0A110A120A290A310A340A370A3A0A3B0A3D0A43-0A460A490A4A0A4E-0A500A52-0A580A5D0A5F-0A650A76-0A800A840A8E0A920AA90AB10AB40ABA0ABB0AC60ACA0ACE0ACF0AD1-0ADF0AE40AE50AF2-0B000B040B0D0B0E0B110B120B290B310B340B3A0B3B0B450B460B490B4A0B4E-0B550B58-0B5B0B5E0B640B650B78-0B810B840B8B-0B8D0B910B96-0B980B9B0B9D0BA0-0BA20BA5-0BA70BAB-0BAD0BBA-0BBD0BC3-0BC50BC90BCE0BCF0BD1-0BD60BD8-0BE50BFB-0C000C040C0D0C110C290C340C3A-0C3C0C450C490C4E-0C540C570C5A-0C5F0C640C650C70-0C770C800C810C840C8D0C910CA90CB40CBA0CBB0CC50CC90CCE-0CD40CD7-0CDD0CDF0CE40CE50CF00CF3-0D010D040D0D0D110D3B0D3C0D450D490D4F-0D560D58-0D5F0D640D650D76-0D780D800D810D840D97-0D990DB20DBC0DBE0DBF0DC7-0DC90DCB-0DCE0DD50DD70DE0-0DF10DF5-0E000E3B-0E3E0E5C-0E800E830E850E860E890E8B0E8C0E8E-0E930E980EA00EA40EA60EA80EA90EAC0EBA0EBE0EBF0EC50EC70ECE0ECF0EDA0EDB0EE0-0EFF0F480F6D-0F700F980FBD0FCD0FDB-0FFF10C610C8-10CC10CE10CF1249124E124F12571259125E125F1289128E128F12B112B612B712BF12C112C612C712D7131113161317135B135C137D-137F139A-139F13F5-13FF169D-169F16F1-16FF170D1715-171F1737-173F1754-175F176D17711774-177F17DE17DF17EA-17EF17FA-17FF180F181A-181F1878-187F18AB-18AF18F6-18FF191D-191F192C-192F193C-193F1941-1943196E196F1975-197F19AC-19AF19CA-19CF19DB-19DD1A1C1A1D1A5F1A7D1A7E1A8A-1A8F1A9A-1A9F1AAE-1AFF1B4C-1B4F1B7D-1B7F1BF4-1BFB1C38-1C3A1C4A-1C4C1C80-1CBF1CC8-1CCF1CF7-1CFF1DE7-1DFB1F161F171F1E1F1F1F461F471F4E1F4F1F581F5A1F5C1F5E1F7E1F7F1FB51FC51FD41FD51FDC1FF01FF11FF51FFF2065-206920722073208F209D-209F20BA-20CF20F1-20FF218A-218F23F4-23FF2427-243F244B-245F27002B4D-2B4F2B5A-2BFF2C2F2C5F2CF4-2CF82D262D28-2D2C2D2E2D2F2D68-2D6E2D71-2D7E2D97-2D9F2DA72DAF2DB72DBF2DC72DCF2DD72DDF2E3C-2E7F2E9A2EF4-2EFF2FD6-2FEF2FFC-2FFF3040309730983100-3104312E-3130318F31BB-31BF31E4-31EF321F32FF4DB6-4DBF9FCD-9FFFA48D-A48FA4C7-A4CFA62C-A63FA698-A69EA6F8-A6FFA78FA794-A79FA7AB-A7F7A82C-A82FA83A-A83FA878-A87FA8C5-A8CDA8DA-A8DFA8FC-A8FFA954-A95EA97D-A97FA9CEA9DA-A9DDA9E0-A9FFAA37-AA3FAA4EAA4FAA5AAA5BAA7C-AA7FAAC3-AADAAAF7-AB00AB07AB08AB0FAB10AB17-AB1FAB27AB2F-ABBFABEEABEFABFA-ABFFD7A4-D7AFD7C7-D7CAD7FC-D7FFFA6EFA6FFADA-FAFFFB07-FB12FB18-FB1CFB37FB3DFB3FFB42FB45FBC2-FBD2FD40-FD4FFD90FD91FDC8-FDEFFDFEFDFFFE1A-FE1FFE27-FE2FFE53FE67FE6C-FE6FFE75FEFDFEFEFF00FFBF-FFC1FFC8FFC9FFD0FFD1FFD8FFD9FFDD-FFDFFFE7FFEF-FFF8FFFEFFFF\"\n    }, {\n        //L: \"Letter\", // Included in the Unicode Base addon\n        Ll: \"Lowercase_Letter\",\n        Lu: \"Uppercase_Letter\",\n        Lt: \"Titlecase_Letter\",\n        Lm: \"Modifier_Letter\",\n        Lo: \"Other_Letter\",\n        M: \"Mark\",\n        Mn: \"Nonspacing_Mark\",\n        Mc: \"Spacing_Mark\",\n        Me: \"Enclosing_Mark\",\n        N: \"Number\",\n        Nd: \"Decimal_Number\",\n        Nl: \"Letter_Number\",\n        No: \"Other_Number\",\n        P: \"Punctuation\",\n        Pd: \"Dash_Punctuation\",\n        Ps: \"Open_Punctuation\",\n        Pe: \"Close_Punctuation\",\n        Pi: \"Initial_Punctuation\",\n        Pf: \"Final_Punctuation\",\n        Pc: \"Connector_Punctuation\",\n        Po: \"Other_Punctuation\",\n        S: \"Symbol\",\n        Sm: \"Math_Symbol\",\n        Sc: \"Currency_Symbol\",\n        Sk: \"Modifier_Symbol\",\n        So: \"Other_Symbol\",\n        Z: \"Separator\",\n        Zs: \"Space_Separator\",\n        Zl: \"Line_Separator\",\n        Zp: \"Paragraph_Separator\",\n        C: \"Other\",\n        Cc: \"Control\",\n        Cf: \"Format\",\n        Co: \"Private_Use\",\n        Cs: \"Surrogate\",\n        Cn: \"Unassigned\"\n    });\n\n}(XRegExp));\n\n\n/***** unicode-scripts.js *****/\n\n/*!\n * XRegExp Unicode Scripts v1.2.0\n * (c) 2010-2012 Steven Levithan <http://xregexp.com/>\n * MIT License\n * Uses Unicode 6.1 <http://unicode.org/>\n */\n\n/**\n * Adds support for all Unicode scripts in the Basic Multilingual Plane (U+0000-U+FFFF).\n * E.g., `\\p{Latin}`. Token names are case insensitive, and any spaces, hyphens, and underscores\n * are ignored.\n * @requires XRegExp, XRegExp Unicode Base\n */\n(function (XRegExp) {\n    \"use strict\";\n\n    if (!XRegExp.addUnicodePackage) {\n        throw new ReferenceError(\"Unicode Base must be loaded before Unicode Scripts\");\n    }\n\n    XRegExp.install(\"extensibility\");\n\n    XRegExp.addUnicodePackage({\n        Arabic: \"0600-06040606-060B060D-061A061E0620-063F0641-064A0656-065E066A-066F0671-06DC06DE-06FF0750-077F08A008A2-08AC08E4-08FEFB50-FBC1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFCFE70-FE74FE76-FEFC\",\n        Armenian: \"0531-05560559-055F0561-0587058A058FFB13-FB17\",\n        Balinese: \"1B00-1B4B1B50-1B7C\",\n        Bamum: \"A6A0-A6F7\",\n        Batak: \"1BC0-1BF31BFC-1BFF\",\n        Bengali: \"0981-09830985-098C098F09900993-09A809AA-09B009B209B6-09B909BC-09C409C709C809CB-09CE09D709DC09DD09DF-09E309E6-09FB\",\n        Bopomofo: \"02EA02EB3105-312D31A0-31BA\",\n        Braille: \"2800-28FF\",\n        Buginese: \"1A00-1A1B1A1E1A1F\",\n        Buhid: \"1740-1753\",\n        Canadian_Aboriginal: \"1400-167F18B0-18F5\",\n        Cham: \"AA00-AA36AA40-AA4DAA50-AA59AA5C-AA5F\",\n        Cherokee: \"13A0-13F4\",\n        Common: \"0000-0040005B-0060007B-00A900AB-00B900BB-00BF00D700F702B9-02DF02E5-02E902EC-02FF0374037E038503870589060C061B061F06400660-066906DD096409650E3F0FD5-0FD810FB16EB-16ED173517361802180318051CD31CE11CE9-1CEC1CEE-1CF31CF51CF62000-200B200E-2064206A-20702074-207E2080-208E20A0-20B92100-21252127-2129212C-21312133-214D214F-215F21892190-23F32400-24262440-244A2460-26FF2701-27FF2900-2B4C2B50-2B592E00-2E3B2FF0-2FFB3000-300430063008-30203030-3037303C-303F309B309C30A030FB30FC3190-319F31C0-31E33220-325F327F-32CF3358-33FF4DC0-4DFFA700-A721A788-A78AA830-A839FD3EFD3FFDFDFE10-FE19FE30-FE52FE54-FE66FE68-FE6BFEFFFF01-FF20FF3B-FF40FF5B-FF65FF70FF9EFF9FFFE0-FFE6FFE8-FFEEFFF9-FFFD\",\n        Coptic: \"03E2-03EF2C80-2CF32CF9-2CFF\",\n        Cyrillic: \"0400-04840487-05271D2B1D782DE0-2DFFA640-A697A69F\",\n        Devanagari: \"0900-09500953-09630966-09770979-097FA8E0-A8FB\",\n        Ethiopic: \"1200-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A135D-137C1380-13992D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDEAB01-AB06AB09-AB0EAB11-AB16AB20-AB26AB28-AB2E\",\n        Georgian: \"10A0-10C510C710CD10D0-10FA10FC-10FF2D00-2D252D272D2D\",\n        Glagolitic: \"2C00-2C2E2C30-2C5E\",\n        Greek: \"0370-03730375-0377037A-037D038403860388-038A038C038E-03A103A3-03E103F0-03FF1D26-1D2A1D5D-1D611D66-1D6A1DBF1F00-1F151F18-1F1D1F20-1F451F48-1F4D1F50-1F571F591F5B1F5D1F5F-1F7D1F80-1FB41FB6-1FC41FC6-1FD31FD6-1FDB1FDD-1FEF1FF2-1FF41FF6-1FFE2126\",\n        Gujarati: \"0A81-0A830A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABC-0AC50AC7-0AC90ACB-0ACD0AD00AE0-0AE30AE6-0AF1\",\n        Gurmukhi: \"0A01-0A030A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A3C0A3E-0A420A470A480A4B-0A4D0A510A59-0A5C0A5E0A66-0A75\",\n        Han: \"2E80-2E992E9B-2EF32F00-2FD5300530073021-30293038-303B3400-4DB54E00-9FCCF900-FA6DFA70-FAD9\",\n        Hangul: \"1100-11FF302E302F3131-318E3200-321E3260-327EA960-A97CAC00-D7A3D7B0-D7C6D7CB-D7FBFFA0-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC\",\n        Hanunoo: \"1720-1734\",\n        Hebrew: \"0591-05C705D0-05EA05F0-05F4FB1D-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FB4F\",\n        Hiragana: \"3041-3096309D-309F\",\n        Inherited: \"0300-036F04850486064B-0655065F0670095109521CD0-1CD21CD4-1CE01CE2-1CE81CED1CF41DC0-1DE61DFC-1DFF200C200D20D0-20F0302A-302D3099309AFE00-FE0FFE20-FE26\",\n        Javanese: \"A980-A9CDA9CF-A9D9A9DEA9DF\",\n        Kannada: \"0C820C830C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBC-0CC40CC6-0CC80CCA-0CCD0CD50CD60CDE0CE0-0CE30CE6-0CEF0CF10CF2\",\n        Katakana: \"30A1-30FA30FD-30FF31F0-31FF32D0-32FE3300-3357FF66-FF6FFF71-FF9D\",\n        Kayah_Li: \"A900-A92F\",\n        Khmer: \"1780-17DD17E0-17E917F0-17F919E0-19FF\",\n        Lao: \"0E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB90EBB-0EBD0EC0-0EC40EC60EC8-0ECD0ED0-0ED90EDC-0EDF\",\n        Latin: \"0041-005A0061-007A00AA00BA00C0-00D600D8-00F600F8-02B802E0-02E41D00-1D251D2C-1D5C1D62-1D651D6B-1D771D79-1DBE1E00-1EFF2071207F2090-209C212A212B2132214E2160-21882C60-2C7FA722-A787A78B-A78EA790-A793A7A0-A7AAA7F8-A7FFFB00-FB06FF21-FF3AFF41-FF5A\",\n        Lepcha: \"1C00-1C371C3B-1C491C4D-1C4F\",\n        Limbu: \"1900-191C1920-192B1930-193B19401944-194F\",\n        Lisu: \"A4D0-A4FF\",\n        Malayalam: \"0D020D030D05-0D0C0D0E-0D100D12-0D3A0D3D-0D440D46-0D480D4A-0D4E0D570D60-0D630D66-0D750D79-0D7F\",\n        Mandaic: \"0840-085B085E\",\n        Meetei_Mayek: \"AAE0-AAF6ABC0-ABEDABF0-ABF9\",\n        Mongolian: \"1800180118041806-180E1810-18191820-18771880-18AA\",\n        Myanmar: \"1000-109FAA60-AA7B\",\n        New_Tai_Lue: \"1980-19AB19B0-19C919D0-19DA19DE19DF\",\n        Nko: \"07C0-07FA\",\n        Ogham: \"1680-169C\",\n        Ol_Chiki: \"1C50-1C7F\",\n        Oriya: \"0B01-0B030B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3C-0B440B470B480B4B-0B4D0B560B570B5C0B5D0B5F-0B630B66-0B77\",\n        Phags_Pa: \"A840-A877\",\n        Rejang: \"A930-A953A95F\",\n        Runic: \"16A0-16EA16EE-16F0\",\n        Samaritan: \"0800-082D0830-083E\",\n        Saurashtra: \"A880-A8C4A8CE-A8D9\",\n        Sinhala: \"0D820D830D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60DCA0DCF-0DD40DD60DD8-0DDF0DF2-0DF4\",\n        Sundanese: \"1B80-1BBF1CC0-1CC7\",\n        Syloti_Nagri: \"A800-A82B\",\n        Syriac: \"0700-070D070F-074A074D-074F\",\n        Tagalog: \"1700-170C170E-1714\",\n        Tagbanwa: \"1760-176C176E-177017721773\",\n        Tai_Le: \"1950-196D1970-1974\",\n        Tai_Tham: \"1A20-1A5E1A60-1A7C1A7F-1A891A90-1A991AA0-1AAD\",\n        Tai_Viet: \"AA80-AAC2AADB-AADF\",\n        Tamil: \"0B820B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BBE-0BC20BC6-0BC80BCA-0BCD0BD00BD70BE6-0BFA\",\n        Telugu: \"0C01-0C030C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D-0C440C46-0C480C4A-0C4D0C550C560C580C590C60-0C630C66-0C6F0C78-0C7F\",\n        Thaana: \"0780-07B1\",\n        Thai: \"0E01-0E3A0E40-0E5B\",\n        Tibetan: \"0F00-0F470F49-0F6C0F71-0F970F99-0FBC0FBE-0FCC0FCE-0FD40FD90FDA\",\n        Tifinagh: \"2D30-2D672D6F2D702D7F\",\n        Vai: \"A500-A62B\",\n        Yi: \"A000-A48CA490-A4C6\"\n    });\n\n}(XRegExp));\n\n\n/***** unicode-blocks.js *****/\n\n/*!\n * XRegExp Unicode Blocks v1.2.0\n * (c) 2010-2012 Steven Levithan <http://xregexp.com/>\n * MIT License\n * Uses Unicode 6.1 <http://unicode.org/>\n */\n\n/**\n * Adds support for all Unicode blocks in the Basic Multilingual Plane (U+0000-U+FFFF). Unicode\n * blocks use the prefix \"In\". E.g., `\\p{InBasicLatin}`. Token names are case insensitive, and any\n * spaces, hyphens, and underscores are ignored.\n * @requires XRegExp, XRegExp Unicode Base\n */\n(function (XRegExp) {\n    \"use strict\";\n\n    if (!XRegExp.addUnicodePackage) {\n        throw new ReferenceError(\"Unicode Base must be loaded before Unicode Blocks\");\n    }\n\n    XRegExp.install(\"extensibility\");\n\n    XRegExp.addUnicodePackage({\n        InBasic_Latin: \"0000-007F\",\n        InLatin_1_Supplement: \"0080-00FF\",\n        InLatin_Extended_A: \"0100-017F\",\n        InLatin_Extended_B: \"0180-024F\",\n        InIPA_Extensions: \"0250-02AF\",\n        InSpacing_Modifier_Letters: \"02B0-02FF\",\n        InCombining_Diacritical_Marks: \"0300-036F\",\n        InGreek_and_Coptic: \"0370-03FF\",\n        InCyrillic: \"0400-04FF\",\n        InCyrillic_Supplement: \"0500-052F\",\n        InArmenian: \"0530-058F\",\n        InHebrew: \"0590-05FF\",\n        InArabic: \"0600-06FF\",\n        InSyriac: \"0700-074F\",\n        InArabic_Supplement: \"0750-077F\",\n        InThaana: \"0780-07BF\",\n        InNKo: \"07C0-07FF\",\n        InSamaritan: \"0800-083F\",\n        InMandaic: \"0840-085F\",\n        InArabic_Extended_A: \"08A0-08FF\",\n        InDevanagari: \"0900-097F\",\n        InBengali: \"0980-09FF\",\n        InGurmukhi: \"0A00-0A7F\",\n        InGujarati: \"0A80-0AFF\",\n        InOriya: \"0B00-0B7F\",\n        InTamil: \"0B80-0BFF\",\n        InTelugu: \"0C00-0C7F\",\n        InKannada: \"0C80-0CFF\",\n        InMalayalam: \"0D00-0D7F\",\n        InSinhala: \"0D80-0DFF\",\n        InThai: \"0E00-0E7F\",\n        InLao: \"0E80-0EFF\",\n        InTibetan: \"0F00-0FFF\",\n        InMyanmar: \"1000-109F\",\n        InGeorgian: \"10A0-10FF\",\n        InHangul_Jamo: \"1100-11FF\",\n        InEthiopic: \"1200-137F\",\n        InEthiopic_Supplement: \"1380-139F\",\n        InCherokee: \"13A0-13FF\",\n        InUnified_Canadian_Aboriginal_Syllabics: \"1400-167F\",\n        InOgham: \"1680-169F\",\n        InRunic: \"16A0-16FF\",\n        InTagalog: \"1700-171F\",\n        InHanunoo: \"1720-173F\",\n        InBuhid: \"1740-175F\",\n        InTagbanwa: \"1760-177F\",\n        InKhmer: \"1780-17FF\",\n        InMongolian: \"1800-18AF\",\n        InUnified_Canadian_Aboriginal_Syllabics_Extended: \"18B0-18FF\",\n        InLimbu: \"1900-194F\",\n        InTai_Le: \"1950-197F\",\n        InNew_Tai_Lue: \"1980-19DF\",\n        InKhmer_Symbols: \"19E0-19FF\",\n        InBuginese: \"1A00-1A1F\",\n        InTai_Tham: \"1A20-1AAF\",\n        InBalinese: \"1B00-1B7F\",\n        InSundanese: \"1B80-1BBF\",\n        InBatak: \"1BC0-1BFF\",\n        InLepcha: \"1C00-1C4F\",\n        InOl_Chiki: \"1C50-1C7F\",\n        InSundanese_Supplement: \"1CC0-1CCF\",\n        InVedic_Extensions: \"1CD0-1CFF\",\n        InPhonetic_Extensions: \"1D00-1D7F\",\n        InPhonetic_Extensions_Supplement: \"1D80-1DBF\",\n        InCombining_Diacritical_Marks_Supplement: \"1DC0-1DFF\",\n        InLatin_Extended_Additional: \"1E00-1EFF\",\n        InGreek_Extended: \"1F00-1FFF\",\n        InGeneral_Punctuation: \"2000-206F\",\n        InSuperscripts_and_Subscripts: \"2070-209F\",\n        InCurrency_Symbols: \"20A0-20CF\",\n        InCombining_Diacritical_Marks_for_Symbols: \"20D0-20FF\",\n        InLetterlike_Symbols: \"2100-214F\",\n        InNumber_Forms: \"2150-218F\",\n        InArrows: \"2190-21FF\",\n        InMathematical_Operators: \"2200-22FF\",\n        InMiscellaneous_Technical: \"2300-23FF\",\n        InControl_Pictures: \"2400-243F\",\n        InOptical_Character_Recognition: \"2440-245F\",\n        InEnclosed_Alphanumerics: \"2460-24FF\",\n        InBox_Drawing: \"2500-257F\",\n        InBlock_Elements: \"2580-259F\",\n        InGeometric_Shapes: \"25A0-25FF\",\n        InMiscellaneous_Symbols: \"2600-26FF\",\n        InDingbats: \"2700-27BF\",\n        InMiscellaneous_Mathematical_Symbols_A: \"27C0-27EF\",\n        InSupplemental_Arrows_A: \"27F0-27FF\",\n        InBraille_Patterns: \"2800-28FF\",\n        InSupplemental_Arrows_B: \"2900-297F\",\n        InMiscellaneous_Mathematical_Symbols_B: \"2980-29FF\",\n        InSupplemental_Mathematical_Operators: \"2A00-2AFF\",\n        InMiscellaneous_Symbols_and_Arrows: \"2B00-2BFF\",\n        InGlagolitic: \"2C00-2C5F\",\n        InLatin_Extended_C: \"2C60-2C7F\",\n        InCoptic: \"2C80-2CFF\",\n        InGeorgian_Supplement: \"2D00-2D2F\",\n        InTifinagh: \"2D30-2D7F\",\n        InEthiopic_Extended: \"2D80-2DDF\",\n        InCyrillic_Extended_A: \"2DE0-2DFF\",\n        InSupplemental_Punctuation: \"2E00-2E7F\",\n        InCJK_Radicals_Supplement: \"2E80-2EFF\",\n        InKangxi_Radicals: \"2F00-2FDF\",\n        InIdeographic_Description_Characters: \"2FF0-2FFF\",\n        InCJK_Symbols_and_Punctuation: \"3000-303F\",\n        InHiragana: \"3040-309F\",\n        InKatakana: \"30A0-30FF\",\n        InBopomofo: \"3100-312F\",\n        InHangul_Compatibility_Jamo: \"3130-318F\",\n        InKanbun: \"3190-319F\",\n        InBopomofo_Extended: \"31A0-31BF\",\n        InCJK_Strokes: \"31C0-31EF\",\n        InKatakana_Phonetic_Extensions: \"31F0-31FF\",\n        InEnclosed_CJK_Letters_and_Months: \"3200-32FF\",\n        InCJK_Compatibility: \"3300-33FF\",\n        InCJK_Unified_Ideographs_Extension_A: \"3400-4DBF\",\n        InYijing_Hexagram_Symbols: \"4DC0-4DFF\",\n        InCJK_Unified_Ideographs: \"4E00-9FFF\",\n        InYi_Syllables: \"A000-A48F\",\n        InYi_Radicals: \"A490-A4CF\",\n        InLisu: \"A4D0-A4FF\",\n        InVai: \"A500-A63F\",\n        InCyrillic_Extended_B: \"A640-A69F\",\n        InBamum: \"A6A0-A6FF\",\n        InModifier_Tone_Letters: \"A700-A71F\",\n        InLatin_Extended_D: \"A720-A7FF\",\n        InSyloti_Nagri: \"A800-A82F\",\n        InCommon_Indic_Number_Forms: \"A830-A83F\",\n        InPhags_pa: \"A840-A87F\",\n        InSaurashtra: \"A880-A8DF\",\n        InDevanagari_Extended: \"A8E0-A8FF\",\n        InKayah_Li: \"A900-A92F\",\n        InRejang: \"A930-A95F\",\n        InHangul_Jamo_Extended_A: \"A960-A97F\",\n        InJavanese: \"A980-A9DF\",\n        InCham: \"AA00-AA5F\",\n        InMyanmar_Extended_A: \"AA60-AA7F\",\n        InTai_Viet: \"AA80-AADF\",\n        InMeetei_Mayek_Extensions: \"AAE0-AAFF\",\n        InEthiopic_Extended_A: \"AB00-AB2F\",\n        InMeetei_Mayek: \"ABC0-ABFF\",\n        InHangul_Syllables: \"AC00-D7AF\",\n        InHangul_Jamo_Extended_B: \"D7B0-D7FF\",\n        InHigh_Surrogates: \"D800-DB7F\",\n        InHigh_Private_Use_Surrogates: \"DB80-DBFF\",\n        InLow_Surrogates: \"DC00-DFFF\",\n        InPrivate_Use_Area: \"E000-F8FF\",\n        InCJK_Compatibility_Ideographs: \"F900-FAFF\",\n        InAlphabetic_Presentation_Forms: \"FB00-FB4F\",\n        InArabic_Presentation_Forms_A: \"FB50-FDFF\",\n        InVariation_Selectors: \"FE00-FE0F\",\n        InVertical_Forms: \"FE10-FE1F\",\n        InCombining_Half_Marks: \"FE20-FE2F\",\n        InCJK_Compatibility_Forms: \"FE30-FE4F\",\n        InSmall_Form_Variants: \"FE50-FE6F\",\n        InArabic_Presentation_Forms_B: \"FE70-FEFF\",\n        InHalfwidth_and_Fullwidth_Forms: \"FF00-FFEF\",\n        InSpecials: \"FFF0-FFFF\"\n    });\n\n}(XRegExp));\n\n\n/***** unicode-properties.js *****/\n\n/*!\n * XRegExp Unicode Properties v1.0.0\n * (c) 2012 Steven Levithan <http://xregexp.com/>\n * MIT License\n * Uses Unicode 6.1 <http://unicode.org/>\n */\n\n/**\n * Adds Unicode properties necessary to meet Level 1 Unicode support (detailed in UTS#18 RL1.2).\n * Includes code points from the Basic Multilingual Plane (U+0000-U+FFFF) only. Token names are\n * case insensitive, and any spaces, hyphens, and underscores are ignored.\n * @requires XRegExp, XRegExp Unicode Base\n */\n(function (XRegExp) {\n    \"use strict\";\n\n    if (!XRegExp.addUnicodePackage) {\n        throw new ReferenceError(\"Unicode Base must be loaded before Unicode Properties\");\n    }\n\n    XRegExp.install(\"extensibility\");\n\n    XRegExp.addUnicodePackage({\n        Alphabetic: \"0041-005A0061-007A00AA00B500BA00C0-00D600D8-00F600F8-02C102C6-02D102E0-02E402EC02EE03450370-037403760377037A-037D03860388-038A038C038E-03A103A3-03F503F7-0481048A-05270531-055605590561-058705B0-05BD05BF05C105C205C405C505C705D0-05EA05F0-05F20610-061A0620-06570659-065F066E-06D306D5-06DC06E1-06E806ED-06EF06FA-06FC06FF0710-073F074D-07B107CA-07EA07F407F507FA0800-0817081A-082C0840-085808A008A2-08AC08E4-08E908F0-08FE0900-093B093D-094C094E-09500955-09630971-09770979-097F0981-09830985-098C098F09900993-09A809AA-09B009B209B6-09B909BD-09C409C709C809CB09CC09CE09D709DC09DD09DF-09E309F009F10A01-0A030A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A3E-0A420A470A480A4B0A4C0A510A59-0A5C0A5E0A70-0A750A81-0A830A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABD-0AC50AC7-0AC90ACB0ACC0AD00AE0-0AE30B01-0B030B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3D-0B440B470B480B4B0B4C0B560B570B5C0B5D0B5F-0B630B710B820B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BBE-0BC20BC6-0BC80BCA-0BCC0BD00BD70C01-0C030C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D-0C440C46-0C480C4A-0C4C0C550C560C580C590C60-0C630C820C830C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBD-0CC40CC6-0CC80CCA-0CCC0CD50CD60CDE0CE0-0CE30CF10CF20D020D030D05-0D0C0D0E-0D100D12-0D3A0D3D-0D440D46-0D480D4A-0D4C0D4E0D570D60-0D630D7A-0D7F0D820D830D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60DCF-0DD40DD60DD8-0DDF0DF20DF30E01-0E3A0E40-0E460E4D0E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB90EBB-0EBD0EC0-0EC40EC60ECD0EDC-0EDF0F000F40-0F470F49-0F6C0F71-0F810F88-0F970F99-0FBC1000-10361038103B-103F1050-10621065-1068106E-1086108E109C109D10A0-10C510C710CD10D0-10FA10FC-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A135F1380-138F13A0-13F41401-166C166F-167F1681-169A16A0-16EA16EE-16F01700-170C170E-17131720-17331740-17531760-176C176E-1770177217731780-17B317B6-17C817D717DC1820-18771880-18AA18B0-18F51900-191C1920-192B1930-19381950-196D1970-19741980-19AB19B0-19C91A00-1A1B1A20-1A5E1A61-1A741AA71B00-1B331B35-1B431B45-1B4B1B80-1BA91BAC-1BAF1BBA-1BE51BE7-1BF11C00-1C351C4D-1C4F1C5A-1C7D1CE9-1CEC1CEE-1CF31CF51CF61D00-1DBF1E00-1F151F18-1F1D1F20-1F451F48-1F4D1F50-1F571F591F5B1F5D1F5F-1F7D1F80-1FB41FB6-1FBC1FBE1FC2-1FC41FC6-1FCC1FD0-1FD31FD6-1FDB1FE0-1FEC1FF2-1FF41FF6-1FFC2071207F2090-209C21022107210A-211321152119-211D212421262128212A-212D212F-2139213C-213F2145-2149214E2160-218824B6-24E92C00-2C2E2C30-2C5E2C60-2CE42CEB-2CEE2CF22CF32D00-2D252D272D2D2D30-2D672D6F2D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE2DE0-2DFF2E2F3005-30073021-30293031-30353038-303C3041-3096309D-309F30A1-30FA30FC-30FF3105-312D3131-318E31A0-31BA31F0-31FF3400-4DB54E00-9FCCA000-A48CA4D0-A4FDA500-A60CA610-A61FA62AA62BA640-A66EA674-A67BA67F-A697A69F-A6EFA717-A71FA722-A788A78B-A78EA790-A793A7A0-A7AAA7F8-A801A803-A805A807-A80AA80C-A827A840-A873A880-A8C3A8F2-A8F7A8FBA90A-A92AA930-A952A960-A97CA980-A9B2A9B4-A9BFA9CFAA00-AA36AA40-AA4DAA60-AA76AA7AAA80-AABEAAC0AAC2AADB-AADDAAE0-AAEFAAF2-AAF5AB01-AB06AB09-AB0EAB11-AB16AB20-AB26AB28-AB2EABC0-ABEAAC00-D7A3D7B0-D7C6D7CB-D7FBF900-FA6DFA70-FAD9FB00-FB06FB13-FB17FB1D-FB28FB2A-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBB1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFBFE70-FE74FE76-FEFCFF21-FF3AFF41-FF5AFF66-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC\",\n        Uppercase: \"0041-005A00C0-00D600D8-00DE01000102010401060108010A010C010E01100112011401160118011A011C011E01200122012401260128012A012C012E01300132013401360139013B013D013F0141014301450147014A014C014E01500152015401560158015A015C015E01600162016401660168016A016C016E017001720174017601780179017B017D018101820184018601870189-018B018E-0191019301940196-0198019C019D019F01A001A201A401A601A701A901AC01AE01AF01B1-01B301B501B701B801BC01C401C701CA01CD01CF01D101D301D501D701D901DB01DE01E001E201E401E601E801EA01EC01EE01F101F401F6-01F801FA01FC01FE02000202020402060208020A020C020E02100212021402160218021A021C021E02200222022402260228022A022C022E02300232023A023B023D023E02410243-02460248024A024C024E03700372037603860388-038A038C038E038F0391-03A103A3-03AB03CF03D2-03D403D803DA03DC03DE03E003E203E403E603E803EA03EC03EE03F403F703F903FA03FD-042F04600462046404660468046A046C046E04700472047404760478047A047C047E0480048A048C048E04900492049404960498049A049C049E04A004A204A404A604A804AA04AC04AE04B004B204B404B604B804BA04BC04BE04C004C104C304C504C704C904CB04CD04D004D204D404D604D804DA04DC04DE04E004E204E404E604E804EA04EC04EE04F004F204F404F604F804FA04FC04FE05000502050405060508050A050C050E05100512051405160518051A051C051E05200522052405260531-055610A0-10C510C710CD1E001E021E041E061E081E0A1E0C1E0E1E101E121E141E161E181E1A1E1C1E1E1E201E221E241E261E281E2A1E2C1E2E1E301E321E341E361E381E3A1E3C1E3E1E401E421E441E461E481E4A1E4C1E4E1E501E521E541E561E581E5A1E5C1E5E1E601E621E641E661E681E6A1E6C1E6E1E701E721E741E761E781E7A1E7C1E7E1E801E821E841E861E881E8A1E8C1E8E1E901E921E941E9E1EA01EA21EA41EA61EA81EAA1EAC1EAE1EB01EB21EB41EB61EB81EBA1EBC1EBE1EC01EC21EC41EC61EC81ECA1ECC1ECE1ED01ED21ED41ED61ED81EDA1EDC1EDE1EE01EE21EE41EE61EE81EEA1EEC1EEE1EF01EF21EF41EF61EF81EFA1EFC1EFE1F08-1F0F1F18-1F1D1F28-1F2F1F38-1F3F1F48-1F4D1F591F5B1F5D1F5F1F68-1F6F1FB8-1FBB1FC8-1FCB1FD8-1FDB1FE8-1FEC1FF8-1FFB21022107210B-210D2110-211221152119-211D212421262128212A-212D2130-2133213E213F21452160-216F218324B6-24CF2C00-2C2E2C602C62-2C642C672C692C6B2C6D-2C702C722C752C7E-2C802C822C842C862C882C8A2C8C2C8E2C902C922C942C962C982C9A2C9C2C9E2CA02CA22CA42CA62CA82CAA2CAC2CAE2CB02CB22CB42CB62CB82CBA2CBC2CBE2CC02CC22CC42CC62CC82CCA2CCC2CCE2CD02CD22CD42CD62CD82CDA2CDC2CDE2CE02CE22CEB2CED2CF2A640A642A644A646A648A64AA64CA64EA650A652A654A656A658A65AA65CA65EA660A662A664A666A668A66AA66CA680A682A684A686A688A68AA68CA68EA690A692A694A696A722A724A726A728A72AA72CA72EA732A734A736A738A73AA73CA73EA740A742A744A746A748A74AA74CA74EA750A752A754A756A758A75AA75CA75EA760A762A764A766A768A76AA76CA76EA779A77BA77DA77EA780A782A784A786A78BA78DA790A792A7A0A7A2A7A4A7A6A7A8A7AAFF21-FF3A\",\n        Lowercase: \"0061-007A00AA00B500BA00DF-00F600F8-00FF01010103010501070109010B010D010F01110113011501170119011B011D011F01210123012501270129012B012D012F01310133013501370138013A013C013E014001420144014601480149014B014D014F01510153015501570159015B015D015F01610163016501670169016B016D016F0171017301750177017A017C017E-0180018301850188018C018D019201950199-019B019E01A101A301A501A801AA01AB01AD01B001B401B601B901BA01BD-01BF01C601C901CC01CE01D001D201D401D601D801DA01DC01DD01DF01E101E301E501E701E901EB01ED01EF01F001F301F501F901FB01FD01FF02010203020502070209020B020D020F02110213021502170219021B021D021F02210223022502270229022B022D022F02310233-0239023C023F0240024202470249024B024D024F-02930295-02B802C002C102E0-02E40345037103730377037A-037D039003AC-03CE03D003D103D5-03D703D903DB03DD03DF03E103E303E503E703E903EB03ED03EF-03F303F503F803FB03FC0430-045F04610463046504670469046B046D046F04710473047504770479047B047D047F0481048B048D048F04910493049504970499049B049D049F04A104A304A504A704A904AB04AD04AF04B104B304B504B704B904BB04BD04BF04C204C404C604C804CA04CC04CE04CF04D104D304D504D704D904DB04DD04DF04E104E304E504E704E904EB04ED04EF04F104F304F504F704F904FB04FD04FF05010503050505070509050B050D050F05110513051505170519051B051D051F05210523052505270561-05871D00-1DBF1E011E031E051E071E091E0B1E0D1E0F1E111E131E151E171E191E1B1E1D1E1F1E211E231E251E271E291E2B1E2D1E2F1E311E331E351E371E391E3B1E3D1E3F1E411E431E451E471E491E4B1E4D1E4F1E511E531E551E571E591E5B1E5D1E5F1E611E631E651E671E691E6B1E6D1E6F1E711E731E751E771E791E7B1E7D1E7F1E811E831E851E871E891E8B1E8D1E8F1E911E931E95-1E9D1E9F1EA11EA31EA51EA71EA91EAB1EAD1EAF1EB11EB31EB51EB71EB91EBB1EBD1EBF1EC11EC31EC51EC71EC91ECB1ECD1ECF1ED11ED31ED51ED71ED91EDB1EDD1EDF1EE11EE31EE51EE71EE91EEB1EED1EEF1EF11EF31EF51EF71EF91EFB1EFD1EFF-1F071F10-1F151F20-1F271F30-1F371F40-1F451F50-1F571F60-1F671F70-1F7D1F80-1F871F90-1F971FA0-1FA71FB0-1FB41FB61FB71FBE1FC2-1FC41FC61FC71FD0-1FD31FD61FD71FE0-1FE71FF2-1FF41FF61FF72071207F2090-209C210A210E210F2113212F21342139213C213D2146-2149214E2170-217F218424D0-24E92C30-2C5E2C612C652C662C682C6A2C6C2C712C732C742C76-2C7D2C812C832C852C872C892C8B2C8D2C8F2C912C932C952C972C992C9B2C9D2C9F2CA12CA32CA52CA72CA92CAB2CAD2CAF2CB12CB32CB52CB72CB92CBB2CBD2CBF2CC12CC32CC52CC72CC92CCB2CCD2CCF2CD12CD32CD52CD72CD92CDB2CDD2CDF2CE12CE32CE42CEC2CEE2CF32D00-2D252D272D2DA641A643A645A647A649A64BA64DA64FA651A653A655A657A659A65BA65DA65FA661A663A665A667A669A66BA66DA681A683A685A687A689A68BA68DA68FA691A693A695A697A723A725A727A729A72BA72DA72F-A731A733A735A737A739A73BA73DA73FA741A743A745A747A749A74BA74DA74FA751A753A755A757A759A75BA75DA75FA761A763A765A767A769A76BA76DA76F-A778A77AA77CA77FA781A783A785A787A78CA78EA791A793A7A1A7A3A7A5A7A7A7A9A7F8-A7FAFB00-FB06FB13-FB17FF41-FF5A\",\n        White_Space: \"0009-000D0020008500A01680180E2000-200A20282029202F205F3000\",\n        Noncharacter_Code_Point: \"FDD0-FDEFFFFEFFFF\",\n        Default_Ignorable_Code_Point: \"00AD034F115F116017B417B5180B-180D200B-200F202A-202E2060-206F3164FE00-FE0FFEFFFFA0FFF0-FFF8\",\n        // \\p{Any} matches a code unit. To match any code point via surrogate pairs, use (?:[\\0-\\uD7FF\\uDC00-\\uFFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]|[\\uD800-\\uDBFF])\n        Any: \"0000-FFFF\", // \\p{^Any} compiles to [^\\u0000-\\uFFFF]; [\\p{^Any}] to []\n        Ascii: \"0000-007F\",\n        // \\p{Assigned} is equivalent to \\p{^Cn}\n        //Assigned: XRegExp(\"[\\\\p{^Cn}]\").source.replace(/[[\\]]|\\\\u/g, \"\") // Negation inside a character class triggers inversion\n        Assigned: \"0000-0377037A-037E0384-038A038C038E-03A103A3-05270531-05560559-055F0561-05870589058A058F0591-05C705D0-05EA05F0-05F40600-06040606-061B061E-070D070F-074A074D-07B107C0-07FA0800-082D0830-083E0840-085B085E08A008A2-08AC08E4-08FE0900-09770979-097F0981-09830985-098C098F09900993-09A809AA-09B009B209B6-09B909BC-09C409C709C809CB-09CE09D709DC09DD09DF-09E309E6-09FB0A01-0A030A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A3C0A3E-0A420A470A480A4B-0A4D0A510A59-0A5C0A5E0A66-0A750A81-0A830A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABC-0AC50AC7-0AC90ACB-0ACD0AD00AE0-0AE30AE6-0AF10B01-0B030B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3C-0B440B470B480B4B-0B4D0B560B570B5C0B5D0B5F-0B630B66-0B770B820B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BBE-0BC20BC6-0BC80BCA-0BCD0BD00BD70BE6-0BFA0C01-0C030C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D-0C440C46-0C480C4A-0C4D0C550C560C580C590C60-0C630C66-0C6F0C78-0C7F0C820C830C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBC-0CC40CC6-0CC80CCA-0CCD0CD50CD60CDE0CE0-0CE30CE6-0CEF0CF10CF20D020D030D05-0D0C0D0E-0D100D12-0D3A0D3D-0D440D46-0D480D4A-0D4E0D570D60-0D630D66-0D750D79-0D7F0D820D830D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60DCA0DCF-0DD40DD60DD8-0DDF0DF2-0DF40E01-0E3A0E3F-0E5B0E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB90EBB-0EBD0EC0-0EC40EC60EC8-0ECD0ED0-0ED90EDC-0EDF0F00-0F470F49-0F6C0F71-0F970F99-0FBC0FBE-0FCC0FCE-0FDA1000-10C510C710CD10D0-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A135D-137C1380-139913A0-13F41400-169C16A0-16F01700-170C170E-17141720-17361740-17531760-176C176E-1770177217731780-17DD17E0-17E917F0-17F91800-180E1810-18191820-18771880-18AA18B0-18F51900-191C1920-192B1930-193B19401944-196D1970-19741980-19AB19B0-19C919D0-19DA19DE-1A1B1A1E-1A5E1A60-1A7C1A7F-1A891A90-1A991AA0-1AAD1B00-1B4B1B50-1B7C1B80-1BF31BFC-1C371C3B-1C491C4D-1C7F1CC0-1CC71CD0-1CF61D00-1DE61DFC-1F151F18-1F1D1F20-1F451F48-1F4D1F50-1F571F591F5B1F5D1F5F-1F7D1F80-1FB41FB6-1FC41FC6-1FD31FD6-1FDB1FDD-1FEF1FF2-1FF41FF6-1FFE2000-2064206A-20712074-208E2090-209C20A0-20B920D0-20F02100-21892190-23F32400-24262440-244A2460-26FF2701-2B4C2B50-2B592C00-2C2E2C30-2C5E2C60-2CF32CF9-2D252D272D2D2D30-2D672D6F2D702D7F-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE2DE0-2E3B2E80-2E992E9B-2EF32F00-2FD52FF0-2FFB3000-303F3041-30963099-30FF3105-312D3131-318E3190-31BA31C0-31E331F0-321E3220-32FE3300-4DB54DC0-9FCCA000-A48CA490-A4C6A4D0-A62BA640-A697A69F-A6F7A700-A78EA790-A793A7A0-A7AAA7F8-A82BA830-A839A840-A877A880-A8C4A8CE-A8D9A8E0-A8FBA900-A953A95F-A97CA980-A9CDA9CF-A9D9A9DEA9DFAA00-AA36AA40-AA4DAA50-AA59AA5C-AA7BAA80-AAC2AADB-AAF6AB01-AB06AB09-AB0EAB11-AB16AB20-AB26AB28-AB2EABC0-ABEDABF0-ABF9AC00-D7A3D7B0-D7C6D7CB-D7FBD800-FA6DFA70-FAD9FB00-FB06FB13-FB17FB1D-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBC1FBD3-FD3FFD50-FD8FFD92-FDC7FDF0-FDFDFE00-FE19FE20-FE26FE30-FE52FE54-FE66FE68-FE6BFE70-FE74FE76-FEFCFEFFFF01-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDCFFE0-FFE6FFE8-FFEEFFF9-FFFD\"\n    });\n\n}(XRegExp));\n\n\n/***** matchrecursive.js *****/\n\n/*!\n * XRegExp.matchRecursive v0.2.0\n * (c) 2009-2012 Steven Levithan <http://xregexp.com/>\n * MIT License\n */\n\n(function (XRegExp) {\n    \"use strict\";\n\n/**\n * Returns a match detail object composed of the provided values.\n * @private\n */\n    function row(value, name, start, end) {\n        return {value:value, name:name, start:start, end:end};\n    }\n\n/**\n * Returns an array of match strings between outermost left and right delimiters, or an array of\n * objects with detailed match parts and position data. An error is thrown if delimiters are\n * unbalanced within the data.\n * @memberOf XRegExp\n * @param {String} str String to search.\n * @param {String} left Left delimiter as an XRegExp pattern.\n * @param {String} right Right delimiter as an XRegExp pattern.\n * @param {String} [flags] Flags for the left and right delimiters. Use any of: `gimnsxy`.\n * @param {Object} [options] Lets you specify `valueNames` and `escapeChar` options.\n * @returns {Array} Array of matches, or an empty array.\n * @example\n *\n * // Basic usage\n * var str = '(t((e))s)t()(ing)';\n * XRegExp.matchRecursive(str, '\\\\(', '\\\\)', 'g');\n * // -> ['t((e))s', '', 'ing']\n *\n * // Extended information mode with valueNames\n * str = 'Here is <div> <div>an</div></div> example';\n * XRegExp.matchRecursive(str, '<div\\\\s*>', '</div>', 'gi', {\n *   valueNames: ['between', 'left', 'match', 'right']\n * });\n * // -> [\n * // {name: 'between', value: 'Here is ',       start: 0,  end: 8},\n * // {name: 'left',    value: '<div>',          start: 8,  end: 13},\n * // {name: 'match',   value: ' <div>an</div>', start: 13, end: 27},\n * // {name: 'right',   value: '</div>',         start: 27, end: 33},\n * // {name: 'between', value: ' example',       start: 33, end: 41}\n * // ]\n *\n * // Omitting unneeded parts with null valueNames, and using escapeChar\n * str = '...{1}\\\\{{function(x,y){return y+x;}}';\n * XRegExp.matchRecursive(str, '{', '}', 'g', {\n *   valueNames: ['literal', null, 'value', null],\n *   escapeChar: '\\\\'\n * });\n * // -> [\n * // {name: 'literal', value: '...', start: 0, end: 3},\n * // {name: 'value',   value: '1',   start: 4, end: 5},\n * // {name: 'literal', value: '\\\\{', start: 6, end: 8},\n * // {name: 'value',   value: 'function(x,y){return y+x;}', start: 9, end: 35}\n * // ]\n *\n * // Sticky mode via flag y\n * str = '<1><<<2>>><3>4<5>';\n * XRegExp.matchRecursive(str, '<', '>', 'gy');\n * // -> ['1', '<<2>>', '3']\n */\n    XRegExp.matchRecursive = function (str, left, right, flags, options) {\n        flags = flags || \"\";\n        options = options || {};\n        var global = flags.indexOf(\"g\") > -1,\n            sticky = flags.indexOf(\"y\") > -1,\n            basicFlags = flags.replace(/y/g, \"\"), // Flag y controlled internally\n            escapeChar = options.escapeChar,\n            vN = options.valueNames,\n            output = [],\n            openTokens = 0,\n            delimStart = 0,\n            delimEnd = 0,\n            lastOuterEnd = 0,\n            outerStart,\n            innerStart,\n            leftMatch,\n            rightMatch,\n            esc;\n        left = XRegExp(left, basicFlags);\n        right = XRegExp(right, basicFlags);\n\n        if (escapeChar) {\n            if (escapeChar.length > 1) {\n                throw new SyntaxError(\"can't use more than one escape character\");\n            }\n            escapeChar = XRegExp.escape(escapeChar);\n            // Using XRegExp.union safely rewrites backreferences in `left` and `right`\n            esc = new RegExp(\n                \"(?:\" + escapeChar + \"[\\\\S\\\\s]|(?:(?!\" + XRegExp.union([left, right]).source + \")[^\" + escapeChar + \"])+)+\",\n                flags.replace(/[^im]+/g, \"\") // Flags gy not needed here; flags nsx handled by XRegExp\n            );\n        }\n\n        while (true) {\n            // If using an escape character, advance to the delimiter's next starting position,\n            // skipping any escaped characters in between\n            if (escapeChar) {\n                delimEnd += (XRegExp.exec(str, esc, delimEnd, \"sticky\") || [\"\"])[0].length;\n            }\n            leftMatch = XRegExp.exec(str, left, delimEnd);\n            rightMatch = XRegExp.exec(str, right, delimEnd);\n            // Keep the leftmost match only\n            if (leftMatch && rightMatch) {\n                if (leftMatch.index <= rightMatch.index) {\n                    rightMatch = null;\n                } else {\n                    leftMatch = null;\n                }\n            }\n            /* Paths (LM:leftMatch, RM:rightMatch, OT:openTokens):\n            LM | RM | OT | Result\n            1  | 0  | 1  | loop\n            1  | 0  | 0  | loop\n            0  | 1  | 1  | loop\n            0  | 1  | 0  | throw\n            0  | 0  | 1  | throw\n            0  | 0  | 0  | break\n            * Doesn't include the sticky mode special case\n            * Loop ends after the first completed match if `!global` */\n            if (leftMatch || rightMatch) {\n                delimStart = (leftMatch || rightMatch).index;\n                delimEnd = delimStart + (leftMatch || rightMatch)[0].length;\n            } else if (!openTokens) {\n                break;\n            }\n            if (sticky && !openTokens && delimStart > lastOuterEnd) {\n                break;\n            }\n            if (leftMatch) {\n                if (!openTokens) {\n                    outerStart = delimStart;\n                    innerStart = delimEnd;\n                }\n                ++openTokens;\n            } else if (rightMatch && openTokens) {\n                if (!--openTokens) {\n                    if (vN) {\n                        if (vN[0] && outerStart > lastOuterEnd) {\n                            output.push(row(vN[0], str.slice(lastOuterEnd, outerStart), lastOuterEnd, outerStart));\n                        }\n                        if (vN[1]) {\n                            output.push(row(vN[1], str.slice(outerStart, innerStart), outerStart, innerStart));\n                        }\n                        if (vN[2]) {\n                            output.push(row(vN[2], str.slice(innerStart, delimStart), innerStart, delimStart));\n                        }\n                        if (vN[3]) {\n                            output.push(row(vN[3], str.slice(delimStart, delimEnd), delimStart, delimEnd));\n                        }\n                    } else {\n                        output.push(str.slice(innerStart, delimStart));\n                    }\n                    lastOuterEnd = delimEnd;\n                    if (!global) {\n                        break;\n                    }\n                }\n            } else {\n                throw new Error(\"string contains unbalanced delimiters\");\n            }\n            // If the delimiter matched an empty string, avoid an infinite loop\n            if (delimStart === delimEnd) {\n                ++delimEnd;\n            }\n        }\n\n        if (global && !sticky && vN && vN[0] && str.length > lastOuterEnd) {\n            output.push(row(vN[0], str.slice(lastOuterEnd), lastOuterEnd, str.length));\n        }\n\n        return output;\n    };\n\n}(XRegExp));\n\n\n/***** build.js *****/\n\n/*!\n * XRegExp.build v0.1.0\n * (c) 2012 Steven Levithan <http://xregexp.com/>\n * MIT License\n * Inspired by RegExp.create by Lea Verou <http://lea.verou.me/>\n */\n\n(function (XRegExp) {\n    \"use strict\";\n\n    var subparts = /(\\()(?!\\?)|\\\\([1-9]\\d*)|\\\\[\\s\\S]|\\[(?:[^\\\\\\]]|\\\\[\\s\\S])*]/g,\n        parts = XRegExp.union([/\\({{([\\w$]+)}}\\)|{{([\\w$]+)}}/, subparts], \"g\");\n\n/**\n * Strips a leading `^` and trailing unescaped `$`, if both are present.\n * @private\n * @param {String} pattern Pattern to process.\n * @returns {String} Pattern with edge anchors removed.\n */\n    function deanchor(pattern) {\n        var startAnchor = /^(?:\\(\\?:\\))?\\^/, // Leading `^` or `(?:)^` (handles /x cruft)\n            endAnchor = /\\$(?:\\(\\?:\\))?$/; // Trailing `$` or `$(?:)` (handles /x cruft)\n        if (endAnchor.test(pattern.replace(/\\\\[\\s\\S]/g, \"\"))) { // Ensure trailing `$` isn't escaped\n            return pattern.replace(startAnchor, \"\").replace(endAnchor, \"\");\n        }\n        return pattern;\n    }\n\n/**\n * Converts the provided value to an XRegExp.\n * @private\n * @param {String|RegExp} value Value to convert.\n * @returns {RegExp} XRegExp object with XRegExp syntax applied.\n */\n    function asXRegExp(value) {\n        return XRegExp.isRegExp(value) ?\n                (value.xregexp && !value.xregexp.isNative ? value : XRegExp(value.source)) :\n                XRegExp(value);\n    }\n\n/**\n * Builds regexes using named subpatterns, for readability and pattern reuse. Backreferences in the\n * outer pattern and provided subpatterns are automatically renumbered to work correctly. Native\n * flags used by provided subpatterns are ignored in favor of the `flags` argument.\n * @memberOf XRegExp\n * @param {String} pattern XRegExp pattern using `{{name}}` for embedded subpatterns. Allows\n *   `({{name}})` as shorthand for `(?<name>{{name}})`. Patterns cannot be embedded within\n *   character classes.\n * @param {Object} subs Lookup object for named subpatterns. Values can be strings or regexes. A\n *   leading `^` and trailing unescaped `$` are stripped from subpatterns, if both are present.\n * @param {String} [flags] Any combination of XRegExp flags.\n * @returns {RegExp} Regex with interpolated subpatterns.\n * @example\n *\n * var time = XRegExp.build('(?x)^ {{hours}} ({{minutes}}) $', {\n *   hours: XRegExp.build('{{h12}} : | {{h24}}', {\n *     h12: /1[0-2]|0?[1-9]/,\n *     h24: /2[0-3]|[01][0-9]/\n *   }, 'x'),\n *   minutes: /^[0-5][0-9]$/\n * });\n * time.test('10:59'); // -> true\n * XRegExp.exec('10:59', time).minutes; // -> '59'\n */\n    XRegExp.build = function (pattern, subs, flags) {\n        var inlineFlags = /^\\(\\?([\\w$]+)\\)/.exec(pattern),\n            data = {},\n            numCaps = 0, // Caps is short for captures\n            numPriorCaps,\n            numOuterCaps = 0,\n            outerCapsMap = [0],\n            outerCapNames,\n            sub,\n            p;\n\n        // Add flags within a leading mode modifier to the overall pattern's flags\n        if (inlineFlags) {\n            flags = flags || \"\";\n            inlineFlags[1].replace(/./g, function (flag) {\n                flags += (flags.indexOf(flag) > -1 ? \"\" : flag); // Don't add duplicates\n            });\n        }\n\n        for (p in subs) {\n            if (subs.hasOwnProperty(p)) {\n                // Passing to XRegExp enables entended syntax for subpatterns provided as strings\n                // and ensures independent validity, lest an unescaped `(`, `)`, `[`, or trailing\n                // `\\` breaks the `(?:)` wrapper. For subpatterns provided as regexes, it dies on\n                // octals and adds the `xregexp` property, for simplicity\n                sub = asXRegExp(subs[p]);\n                // Deanchoring allows embedding independently useful anchored regexes. If you\n                // really need to keep your anchors, double them (i.e., `^^...$$`)\n                data[p] = {pattern: deanchor(sub.source), names: sub.xregexp.captureNames || []};\n            }\n        }\n\n        // Passing to XRegExp dies on octals and ensures the outer pattern is independently valid;\n        // helps keep this simple. Named captures will be put back\n        pattern = asXRegExp(pattern);\n        outerCapNames = pattern.xregexp.captureNames || [];\n        pattern = pattern.source.replace(parts, function ($0, $1, $2, $3, $4) {\n            var subName = $1 || $2, capName, intro;\n            if (subName) { // Named subpattern\n                if (!data.hasOwnProperty(subName)) {\n                    throw new ReferenceError(\"undefined property \" + $0);\n                }\n                if ($1) { // Named subpattern was wrapped in a capturing group\n                    capName = outerCapNames[numOuterCaps];\n                    outerCapsMap[++numOuterCaps] = ++numCaps;\n                    // If it's a named group, preserve the name. Otherwise, use the subpattern name\n                    // as the capture name\n                    intro = \"(?<\" + (capName || subName) + \">\";\n                } else {\n                    intro = \"(?:\";\n                }\n                numPriorCaps = numCaps;\n                return intro + data[subName].pattern.replace(subparts, function (match, paren, backref) {\n                    if (paren) { // Capturing group\n                        capName = data[subName].names[numCaps - numPriorCaps];\n                        ++numCaps;\n                        if (capName) { // If the current capture has a name, preserve the name\n                            return \"(?<\" + capName + \">\";\n                        }\n                    } else if (backref) { // Backreference\n                        return \"\\\\\" + (+backref + numPriorCaps); // Rewrite the backreference\n                    }\n                    return match;\n                }) + \")\";\n            }\n            if ($3) { // Capturing group\n                capName = outerCapNames[numOuterCaps];\n                outerCapsMap[++numOuterCaps] = ++numCaps;\n                if (capName) { // If the current capture has a name, preserve the name\n                    return \"(?<\" + capName + \">\";\n                }\n            } else if ($4) { // Backreference\n                return \"\\\\\" + outerCapsMap[+$4]; // Rewrite the backreference\n            }\n            return $0;\n        });\n\n        return XRegExp(pattern, flags);\n    };\n\n}(XRegExp));\n\n\n/***** prototypes.js *****/\n\n/*!\n * XRegExp Prototype Methods v1.0.0\n * (c) 2012 Steven Levithan <http://xregexp.com/>\n * MIT License\n */\n\n/**\n * Adds a collection of methods to `XRegExp.prototype`. RegExp objects copied by XRegExp are also\n * augmented with any `XRegExp.prototype` methods. Hence, the following work equivalently:\n *\n * XRegExp('[a-z]', 'ig').xexec('abc');\n * XRegExp(/[a-z]/ig).xexec('abc');\n * XRegExp.globalize(/[a-z]/i).xexec('abc');\n */\n(function (XRegExp) {\n    \"use strict\";\n\n/**\n * Copy properties of `b` to `a`.\n * @private\n * @param {Object} a Object that will receive new properties.\n * @param {Object} b Object whose properties will be copied.\n */\n    function extend(a, b) {\n        for (var p in b) {\n            if (b.hasOwnProperty(p)) {\n                a[p] = b[p];\n            }\n        }\n        //return a;\n    }\n\n    extend(XRegExp.prototype, {\n\n/**\n * Implicitly calls the regex's `test` method with the first value in the provided arguments array.\n * @memberOf XRegExp.prototype\n * @param {*} context Ignored. Accepted only for congruity with `Function.prototype.apply`.\n * @param {Array} args Array with the string to search as its first value.\n * @returns {Boolean} Whether the regex matched the provided value.\n * @example\n *\n * XRegExp('[a-z]').apply(null, ['abc']); // -> true\n */\n        apply: function (context, args) {\n            return this.test(args[0]);\n        },\n\n/**\n * Implicitly calls the regex's `test` method with the provided string.\n * @memberOf XRegExp.prototype\n * @param {*} context Ignored. Accepted only for congruity with `Function.prototype.call`.\n * @param {String} str String to search.\n * @returns {Boolean} Whether the regex matched the provided value.\n * @example\n *\n * XRegExp('[a-z]').call(null, 'abc'); // -> true\n */\n        call: function (context, str) {\n            return this.test(str);\n        },\n\n/**\n * Implicitly calls {@link #XRegExp.forEach}.\n * @memberOf XRegExp.prototype\n * @example\n *\n * XRegExp('\\\\d').forEach('1a2345', function (match, i) {\n *   if (i % 2) this.push(+match[0]);\n * }, []);\n * // -> [2, 4]\n */\n        forEach: function (str, callback, context) {\n            return XRegExp.forEach(str, this, callback, context);\n        },\n\n/**\n * Implicitly calls {@link #XRegExp.globalize}.\n * @memberOf XRegExp.prototype\n * @example\n *\n * var globalCopy = XRegExp('regex').globalize();\n * globalCopy.global; // -> true\n */\n        globalize: function () {\n            return XRegExp.globalize(this);\n        },\n\n/**\n * Implicitly calls {@link #XRegExp.exec}.\n * @memberOf XRegExp.prototype\n * @example\n *\n * var match = XRegExp('U\\\\+(?<hex>[0-9A-F]{4})').xexec('U+2620');\n * match.hex; // -> '2620'\n */\n        xexec: function (str, pos, sticky) {\n            return XRegExp.exec(str, this, pos, sticky);\n        },\n\n/**\n * Implicitly calls {@link #XRegExp.test}.\n * @memberOf XRegExp.prototype\n * @example\n *\n * XRegExp('c').xtest('abc'); // -> true\n */\n        xtest: function (str, pos, sticky) {\n            return XRegExp.test(str, this, pos, sticky);\n        }\n\n    });\n\n}(XRegExp));\n\n"
  },
  {
    "path": "static_cdn/static_root/css/main.css",
    "content": "body {\n    color: #ccc;\n}"
  },
  {
    "path": "static_cdn/static_root/css/stripe-custom-style.css",
    "content": "/**\n * The CSS shown here will not be introduced in the Quickstart guide, but shows\n * how you can use CSS to style your Element's container.\n */\n.StripeElement {\n  background-color: white;\n  padding: 8px 12px;\n  border-radius: 4px;\n  border: 1px solid transparent;\n  box-shadow: 0 1px 3px 0 #e6ebf1;\n  -webkit-transition: box-shadow 150ms ease;\n  transition: box-shadow 150ms ease;\n}\n\n.StripeElement--focus {\n  box-shadow: 0 1px 3px 0 #cfd7df;\n}\n\n.StripeElement--invalid {\n  border-color: #fa755a;\n}\n\n.StripeElement--webkit-autofill {\n  background-color: #fefde5 !important;\n}\n"
  },
  {
    "path": "static_cdn/static_root/js/csrf.ajax.js",
    "content": "$(document).ready(function(){\n    // using jQuery\n    function getCookie(name) {\n        var cookieValue = null;\n        if (document.cookie && document.cookie !== '') {\n            var cookies = document.cookie.split(';');\n            for (var i = 0; i < cookies.length; i++) {\n                var cookie = jQuery.trim(cookies[i]);\n                // Does this cookie string begin with the name we want?\n                if (cookie.substring(0, name.length + 1) === (name + '=')) {\n                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));\n                    break;\n                }\n            }\n        }\n        return cookieValue;\n    }\n    var csrftoken = getCookie('csrftoken');\n\n    function csrfSafeMethod(method) {\n        // these HTTP methods do not require CSRF protection\n        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));\n    }\n    $.ajaxSetup({\n        beforeSend: function(xhr, settings) {\n            if (!csrfSafeMethod(settings.type) && !this.crossDomain) {\n                xhr.setRequestHeader(\"X-CSRFToken\", csrftoken);\n            }\n        }\n    });\n\n})"
  },
  {
    "path": "static_cdn/static_root/js/ecommerce.js",
    "content": "$(document).ready(function(){\n    // Contact Form Handler\n\n    var contactForm = $(\".contact-form\")\n    var contactFormMethod = contactForm.attr(\"method\")\n    var contactFormEndpoint = contactForm.attr(\"action\") // /abc/\n    \n    \n    function displaySubmitting(submitBtn, defaultText, doSubmit){\n      if (doSubmit){\n        submitBtn.addClass(\"disabled\")\n        submitBtn.html(\"<i class='fa fa-spin fa-spinner'></i> Sending...\")\n      } else {\n        submitBtn.removeClass(\"disabled\")\n        submitBtn.html(defaultText)\n      }\n      \n    }\n\n\n    contactForm.submit(function(event){\n      event.preventDefault()\n\n      var contactFormSubmitBtn = contactForm.find(\"[type='submit']\")\n      var contactFormSubmitBtnTxt = contactFormSubmitBtn.text()\n\n\n      var contactFormData = contactForm.serialize()\n      var thisForm = $(this)\n      displaySubmitting(contactFormSubmitBtn, \"\", true)\n      $.ajax({\n        method: contactFormMethod,\n        url:  contactFormEndpoint,\n        data: contactFormData,\n        success: function(data){\n          contactForm[0].reset()\n          $.alert({\n            title: \"Success!\",\n            content: data.message,\n            theme: \"modern\",\n          })\n          setTimeout(function(){\n            displaySubmitting(contactFormSubmitBtn, contactFormSubmitBtnTxt, false)\n          }, 500)\n        },\n        error: function(error){\n          console.log(error.responseJSON)\n          var jsonData = error.responseJSON\n          var msg = \"\"\n\n          $.each(jsonData, function(key, value){ // key, value  array index / object\n            msg += key + \": \" + value[0].message + \"<br/>\"\n          })\n\n          $.alert({\n            title: \"Oops!\",\n            content: msg,\n            theme: \"modern\",\n          })\n\n          setTimeout(function(){\n            displaySubmitting(contactFormSubmitBtn, contactFormSubmitBtnTxt, false)\n          }, 500)\n\n        }\n      })\n    })\n\n\n\n\n    // Auto Search\n    var searchForm = $(\".search-form\")\n    var searchInput = searchForm.find(\"[name='q']\") // input name='q'\n    var typingTimer;\n    var typingInterval = 500 // .5 seconds\n    var searchBtn = searchForm.find(\"[type='submit']\")\n    searchInput.keyup(function(event){\n      // key released\n      clearTimeout(typingTimer)\n\n      typingTimer = setTimeout(perfomSearch, typingInterval)\n    })\n\n    searchInput.keydown(function(event){\n      // key pressed\n      clearTimeout(typingTimer)\n    })\n\n    function displaySearching(){\n      searchBtn.addClass(\"disabled\")\n      searchBtn.html(\"<i class='fa fa-spin fa-spinner'></i> Searching...\")\n    }\n\n    function perfomSearch(){\n      displaySearching()\n      var query = searchInput.val()\n      setTimeout(function(){\n        window.location.href='/search/?q=' + query\n      }, 1000)\n      \n    }\n\n\n  // Cart + Add Products \n  var productForm = $(\".form-product-ajax\") // #form-product-ajax\n\n  function getOwnedProduct(productId, submitSpan){\n    var actionEndpoint = '/orders/endpoint/verify/ownership/'\n    var httpMethod = 'GET'\n    var data = {\n      product_id: productId\n    }\n\n    var isOwner;\n    $.ajax({\n        url: actionEndpoint,\n        method: httpMethod,\n        data: data,\n        success: function(data){\n          console.log(data)\n          console.log(data.owner)\n          if (data.owner){\n            isOwner = true\n            submitSpan.html(\"<a class='btn btn-warning' href='/library/'>In Library</a>\")\n          } else {\n            isOwner = false\n          }\n        },\n        error: function(erorr){\n          console.log(error)\n\n        }\n    })\n    return isOwner\n    \n  }\n\n  $.each(productForm, function(index, object){\n    var $this = $(this)\n    var isUser = $this.attr(\"data-user\")\n    var submitSpan = $this.find(\".submit-span\")\n    var productInput = $this.find(\"[name='product_id']\")\n    var productId = productInput.attr(\"value\")\n    var productIsDigital = productInput.attr(\"data-is-digital\")\n    \n    if (productIsDigital && isUser){\n      var isOwned = getOwnedProduct(productId, submitSpan)\n    }\n  })  \n\n\n  productForm.submit(function(event){\n      event.preventDefault();\n      // console.log(\"Form is not sending\")\n      var thisForm = $(this)\n      // var actionEndpoint = thisForm.attr(\"action\"); // API Endpoint\n      var actionEndpoint = thisForm.attr(\"data-endpoint\")\n      var httpMethod = thisForm.attr(\"method\");\n      var formData = thisForm.serialize();\n\n      $.ajax({\n        url: actionEndpoint,\n        method: httpMethod,\n        data: formData,\n        success: function(data){\n          var submitSpan = thisForm.find(\".submit-span\")\n          if (data.added){\n            submitSpan.html(\"<div class='btn-group'> <a class='btn btn-link' href='/cart/'>In cart</a> <button type='submit' class='btn btn-link'>Remove?</button></div>\")\n          } else {\n            submitSpan.html(\"<button type='submit'  class='btn btn-success'>Add to cart</button>\")\n           }\n          var navbarCount = $(\".navbar-cart-count\")\n          navbarCount.text(data.cartItemCount)\n          var currentPath = window.location.href\n\n          if (currentPath.indexOf(\"cart\") != -1) {\n            refreshCart()\n          }\n        },\n        error: function(errorData){\n          $.alert({\n            title: \"Oops!\",\n            content: \"An error occurred\",\n            theme: \"modern\",\n          })\n        }\n      })\n\n  })\n\n  function refreshCart(){\n    console.log(\"in current cart\")\n    var cartTable = $(\".cart-table\")\n    var cartBody = cartTable.find(\".cart-body\")\n    //cartBody.html(\"<h1>Changed</h1>\")\n    var productRows = cartBody.find(\".cart-product\")\n    var currentUrl = window.location.href\n\n    var refreshCartUrl = '/api/cart/'\n    var refreshCartMethod = \"GET\";\n    var data = {};\n    $.ajax({\n      url: refreshCartUrl,\n      method: refreshCartMethod,\n      data: data,\n      success: function(data){\n        \n        var hiddenCartItemRemoveForm = $(\".cart-item-remove-form\")\n        if (data.products.length > 0){\n            productRows.html(\" \")\n            i = data.products.length\n            $.each(data.products, function(index, value){\n              console.log(value)\n              var newCartItemRemove = hiddenCartItemRemoveForm.clone()\n              newCartItemRemove.css(\"display\", \"block\")\n              // newCartItemRemove.removeClass(\"hidden-class\")\n              newCartItemRemove.find(\".cart-item-product-id\").val(value.id)\n                cartBody.prepend(\"<tr><th scope=\\\"row\\\">\" + i + \"</th><td><a href='\" + value.url + \"'>\" + value.name + \"</a>\" + newCartItemRemove.html() + \"</td><td>\" + value.price + \"</td></tr>\")\n                i --\n            })\n            \n            cartBody.find(\".cart-subtotal\").text(data.subtotal)\n            cartBody.find(\".cart-total\").text(data.total)\n        } else {\n          window.location.href = currentUrl\n        }\n        \n      },\n      error: function(errorData){\n        $.alert({\n            title: \"Oops!\",\n            content: \"An error occurred\",\n            theme: \"modern\",\n          })\n      }\n    })\n\n\n  }\n\n\n\n})\n"
  },
  {
    "path": "static_cdn/static_root/js/ecommerce.main.js",
    "content": "$(document).ready(function(){\n\n\nvar stripeFormModule = $(\".stripe-payment-form\")\nvar stripeModuleToken = stripeFormModule.attr(\"data-token\")\nvar stripeModuleNextUrl = stripeFormModule.attr(\"data-next-url\")\nvar stripeModuleBtnTitle = stripeFormModule.attr(\"data-btn-title\") || \"Add card\"\n\nvar stripeTemplate = $.templates(\"#stripeTemplate\")\nvar stripeTemplateDataContext = {\n    publishKey: stripeModuleToken,\n    nextUrl: stripeModuleNextUrl,\n    btnTitle: stripeModuleBtnTitle\n}\nvar stripeTemplateHtml  = stripeTemplate.render(stripeTemplateDataContext)\nstripeFormModule.html(stripeTemplateHtml)\n\n\n\n\n// https secure site when live\n\nvar paymentForm = $(\".payment-form\")\nif (paymentForm.length > 1){\n    alert(\"Only one payment form is allowed per page\")\n    paymentForm.css('display', 'none')\n}\nelse if (paymentForm.length == 1) {\n\nvar pubKey = paymentForm.attr('data-token')\nvar nextUrl = paymentForm.attr('data-next-url')\n    // Create a Stripe client\nvar stripe = Stripe(pubKey);\n\n// Create an instance of Elements\nvar elements = stripe.elements();\n\n// Custom styling can be passed to options when creating an Element.\n// (Note that this demo uses a wider set of styles than the guide below.)\nvar style = {\n  base: {\n    color: '#32325d',\n    lineHeight: '24px',\n    fontFamily: '\"Helvetica Neue\", Helvetica, sans-serif',\n    fontSmoothing: 'antialiased',\n    fontSize: '16px',\n    '::placeholder': {\n      color: '#aab7c4'\n    }\n  },\n  invalid: {\n    color: '#fa755a',\n    iconColor: '#fa755a'\n  }\n};\n\n// Create an instance of the card Element\nvar card = elements.create('card', {style: style});\n\n// Add an instance of the card Element into the `card-element` <div>\ncard.mount('#card-element');\n\n// Handle real-time validation errors from the card Element.\ncard.addEventListener('change', function(event) {\n  var displayError = document.getElementById('card-errors');\n  if (event.error) {\n    displayError.textContent = event.error.message;\n  } else {\n    displayError.textContent = '';\n  }\n});\n\n// Handle form submission\n// var form = document.getElementById('payment-form');\n// form.addEventListener('submit', function(event) {\n//   event.preventDefault();\n//   // get the btn\n//   // display new btn ui\n//   var loadTime = 1500\n//   var errorHtml = \"<i class='fa fa-warning'></i> An error occured\"\n//   var errorClasses = \"btn btn-danger disabled my-3\"\n//   var loadingHtml = \"<i class='fa fa-spin fa-spinner'></i> Loading...\"\n//   var loadingClasses = \"btn btn-success disabled my-3\"\n\n//   stripe.createToken(card).then(function(result) {\n//     if (result.error) {\n//       // Inform the user if there was an error\n//       var errorElement = document.getElementById('card-errors');\n//       errorElement.textContent = result.error.message;\n//     } else {\n//       // Send the token to your server\n//       stripeTokenHandler(nextUrl, result.token);\n//     }\n//   });\n// });\n\nvar form = $('#payment-form');\nvar btnLoad = form.find(\".btn-load\")\nvar btnLoadDefaultHtml = btnLoad.html()\nvar btnLoadDefaultClasses = btnLoad.attr(\"class\")\n\nform.on('submit', function(event) {\n  event.preventDefault();\n  // get the btn\n  // display new btn ui\n  var $this = $(this)\n  // btnLoad = $this.find('.btn-load')\n  btnLoad.blur()\n  var loadTime = 1500\n  var currentTimeout;\n  var errorHtml = \"<i class='fa fa-warning'></i> An error occured\"\n  var errorClasses = \"btn btn-danger disabled my-3\"\n  var loadingHtml = \"<i class='fa fa-spin fa-spinner'></i> Loading...\"\n  var loadingClasses = \"btn btn-success disabled my-3\"\n\n  stripe.createToken(card).then(function(result) {\n    if (result.error) {\n      // Inform the user if there was an error\n      var errorElement = $('#card-errors');\n      errorElement.textContent = result.error.message;\n      currentTimeout = displayBtnStatus(\n                            btnLoad, \n                            errorHtml, \n                            errorClasses, \n                            1000, \n                            currentTimeout\n                        )\n\n\n    } else {\n      // Send the token to your server\n      currentTimeout = displayBtnStatus(\n                            btnLoad, \n                            loadingHtml, \n                            loadingClasses, \n                            1000, \n                            currentTimeout\n                        )\n\n      stripeTokenHandler(nextUrl, result.token);\n\n    }\n  });\n});\n\n\nfunction displayBtnStatus(element, newHtml, newClasses, loadTime, timeout){\n    // if (timeout){\n    //   clearTimeout(timeout)\n    // }\n    if (!loadTime){\n      loadTime = 1500\n    }\n    //var defaultHtml = element.html()\n    //var defaultClasses = element.attr(\"class\")\n    element.html(newHtml)\n    element.removeClass(btnLoadDefaultClasses)\n    element.addClass(newClasses)\n    return setTimeout(function(){\n        element.html(btnLoadDefaultHtml)\n        element.removeClass(newClasses)\n        element.addClass(btnLoadDefaultClasses)\n    }, loadTime)\n}\n\n\nfunction redirectToNext(nextPath, timeoffset) {\n    // body...\n    if (nextPath){\n    setTimeout(function(){\n                window.location.href = nextPath\n            }, timeoffset)\n    }\n}\n\nfunction stripeTokenHandler(nextUrl, token){\n    // console.log(token.id)\n    var paymentMethodEndpoint = '/billing/payment-method/create/'\n    var data = {\n        'token': token.id\n    }\n    $.ajax({\n        data: data,\n        url: paymentMethodEndpoint,\n        method: \"POST\",\n        success: function(data){\n            var succesMsg = data.message || \"Success! Your card was added.\"\n            card.clear()\n            if (nextUrl){\n                succesMsg = succesMsg + \"<br/><br/><i class='fa fa-spin fa-spinner'></i> Redirecting...\"\n            }\n            if ($.alert){\n                $.alert(succesMsg)\n            } else {\n                alert(succesMsg)\n            }\n            btnLoad.html(btnLoadDefaultHtml)\n            btnLoad.attr('class', btnLoadDefaultClasses)\n            redirectToNext(nextUrl, 1500)\n            \n        },\n        error: function(error){\n            console.log(error)\n            $.alert({title: \"An error occured\", content:\"Please try adding your card again.\"})\n            btnLoad.html(btnLoadDefaultHtml)\n            btnLoad.attr('class', btnLoadDefaultClasses)\n        }\n    })\n}\n}\n\n})"
  }
]