diff --git a/.env b/.env new file mode 100644 index 00000000..784b4a9c --- /dev/null +++ b/.env @@ -0,0 +1 @@ +export DJANGO_SETTINGS_MODULE="infohub.settings" diff --git a/.gitignore b/.gitignore index f22e6d66..43980989 100755 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ *.txt .vagrant* submit/ +*.DS_Store +*/migrations/ +credentials.json diff --git a/.travis.yml b/.travis.yml index b3f649d4..13e627c8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,18 @@ +sudo: false language: python python: - - "2.6" - - "2.7" - - "3.2" - - "3.3" - - "3.4" - - "nightly" - -# command to install dependencies -install: "pip install -r requirements.txt" - -# command to run tests -script: nosetests +# - "2.6" +# - "2.7" + - "3.6" +install: + - "pip3 install -r requirements.txt" +before_script: + - psql -c "create role myuser with createrole createdb login password 'mypassword';" -U postgres + - psql -c "create database webapp;" -U postgres + - export DJANGO_SETTINGS_MODULE="infohub.settings" +script: + - python3 manage.py makemigrations profiles + - python3 manage.py migrate --fake-initial + - python3 manage.py makemigrations infohub malaria_web pcsa pcsa_GHN pcsa_safety_tools + - python3 manage.py migrate --fake-initial +# - python3 manage.py test --settings=infohub.settings diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..11638f78 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,11 @@ +# Contributing Guidelines +* You can join our [slack channel](http://systers.io/slack-systers-opensource/). Each active repo has its own channel to direct questions to (for example #powerup or #portal). +* Remember that this is an inclusive community, committed to creating a safe, positive environment. See the full [Code of Conduct](http://www.systers.io/code-of-conduct.html). +## General Guidelines +* If you’re just getting started work on an issue labeled “First Timers Only” in any project. Additional resources are available on our [website](http://www.systers.io). +* In an active repository (not an archived one), choose an open issue from the issue list, claim it in the comments, and a maintainer will assign it to you. +* After approval you must make continuous notes on your progress in the issue while working. If there is not at least one comment every 3 days, the maintainer can reassign the issue. +* When sending a PR have an appropriate title referencing the issue which it solves. Add “fixes #” in the commit body, so that when the PR gets merged, the issue gets closed automatically. Do not do this if the PR solves only a part of the issue. See more information on commit guidelines [here](https://udacity.github.io/git-styleguide/). +* If you’d like to create a new issue, please go through our issue list first (open as well as closed) and make sure the issues you are reporting do not replicate the existing issues. +* Have a short description on what has gone wrong (like a root cause analysis and description of the fix), if that information is not already present in the issue. +* If you have issues on multiple pages, report them separately. Do not combine them into a single issue. diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..7ed12e87 --- /dev/null +++ b/ISSUE_TEMPLATE.md @@ -0,0 +1,20 @@ +## Description +As a [USER], +I need [TO DO THIS], +so that I can [ACCOMPLISH THAT]. + +## Mocks +[INSERT RELEVANT PNG FILE] + +## Acceptance Criteria +### Update [Required] +- [ ] [LIST ITEMS] +### Enhancement to Update [Optional] +- [ ] [LIST ITEMS] + +## Definition of Done +- [ ] All of the required items are completed. +- [ ] Approval by 1 mentor. + +## Estimation +[INSERT NUMBER HERE] hours diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..a83ffecc --- /dev/null +++ b/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,42 @@ +### Description +Include a summary of the change and relevant motivation/context. List any dependencies that are required for this change. + +Fixes # [ISSUE] + +### Type of Change: +**Delete irrelevant options.** + +- Code +- Quality Assurance +- User Interface +- Outreach +- Documentation + + +**Code/Quality Assurance Only** +- Bug fix (non-breaking change which fixes an issue) +- This change requires a documentation update (software upgrade on readme file) +- New feature (non-breaking change which adds functionality pre-approved by mentors) + + + +### How Has This Been Tested? +Describe the tests you ran to verify your changes. Provide instructions or GIFs so we can reproduce. List any relevant details for your test. + + +### Checklist: +**Delete irrelevant options.** + +- [ ] My PR follows the style guidelines of this project +- [ ] I have performed a self-review of my own code or materials +- [ ] I have commented my code or provided relevant documentation, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation +- [ ] Any dependent changes have been merged + + +**Code/Quality Assurance Only** +- [ ] My changes generate no new warnings +- [ ] My PR currently breaks something (fix or feature that would cause existing functionality to not work as expected) +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] New and existing unit tests pass locally with my changes +- [ ] Any dependent changes have been published in downstream modules diff --git a/Procfile b/Procfile deleted file mode 100644 index 3dd6c63f..00000000 --- a/Procfile +++ /dev/null @@ -1 +0,0 @@ -web: gunicorn infohub.wsgi diff --git a/README.md b/README.md index e25f4316..15fb9179 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,25 @@ -

Malaria App Project

+# Mobile App Control Center (MACC) [![Build Status](https://travis-ci.org/systers/macc.svg?branch=develop)](https://travis-ci.org/systers/macc) -The malaria-app-readme repository is intended to be the central repo for discussions, decision making, and feedback about the project goals and features so that the user experience across platforms is uniform. Comments and coding for a specific platform can happen at the repositories linked to below. +MACC is a backend platform for the Peace Corps mobile applications - Malaria and FirstAide. The Mobile App Control Center allows the volunteers at Peace Corps HQ to send or edit any information in their mobile applications through a set of APIs. -

Link to README Repo:

https://github.com/PeaceCorps/malaria-app-readme +## On Malaria App +MACC works on Malaria Prevention application as infoHub, a portal where posts can be added and notified to the mobile app users(volunteers). Posts on infoHub mainly focus on malaria prevention tips and malaria awareness. -Please keep all discussion regarding features that will be cross-platform on that repository, and code-specific discussion on this one. +## On FirstAide App +MACC works on PCSA mobile and web apps, MACC makes the mobile apps fully dynamic and all the information present in the mobile apps is fetched from MACC through APIs. +Installation Guide - [here](https://github.com/systers/macc/blob/develop/docs/Installation%20Guide.md) +Documentation - [Here](https://drive.google.com/open?id=0B6cRm7QFaag1YWNTZ2stcmdieTQ) *(Extract .zip - > open _build/html/index.html )* -

Application Description

+API Documentation - [here](https://docs.google.com/document/d/1uQ42HQGIEOWoD-PtRRGoKLN15S-EhEkWgsIxiceNMGI/edit?usp=sharing) -Peace Corps is looking to build a mobile app that will aid the Volunteer in sustaining life-saving malaria prevention tactics over their 2+ years of service. Prevention is focused on sustained use of preventive medications, which are taken either daily or weekly, depending on the medicine. The application will feature a reminder system; an ability to indicate that medication was taken on time or missed; the ability for the volunteer to track their usage history; a trip indicator to help remind volunteers to pack certain supplies to prevent malaria if they leave their home village; and an Info Hub that will provide accurate information about Malaria and the medications they are taking. +Contribution Guide - [here](https://github.com/systers/macc/blob/develop/docs/Contribution.md) -Included in this repository are Adobe Illustrator (.ai), and Adobe PDF (.pdf) files that were created by University of Michigan design students to meet the requirements listed above. These resources are intended to be the building blocks of iOS and Android applications. +## Current Status +Final Demos given by 2017 GSoC students on project status - +Yatna's Demo - [Watch Here](https://www.youtube.com/watch?v=f7wgeBlxm1g&t=355s) +Gunpreet's Demo - [Watch Here](https://www.youtube.com/watch?v=r_DrvDd96b8) -Also included in this repository for reference and background are two recent studies conducted by the CDC pertaining to use of preventative tactics by volunteers and their reasons for compliance or non-compliance with taking their medicine. -

Asset Information

-Included in this repository are files to help you get started: - - -

Contact Information:

- - -Patrick Choquette - -Director of the Office of Innovation - -pchoquette@peacecorps.gov - - -Matthew McAllister - -Special Assistant in the Office of Innovation - -mmcallister@peacecorps.gov diff --git a/Vaibhavi_Desai_Contributions.txt b/Vaibhavi_Desai_Contributions.txt deleted file mode 100644 index 3206f9ee..00000000 --- a/Vaibhavi_Desai_Contributions.txt +++ /dev/null @@ -1,58419 +0,0 @@ -commit d627ba6d0dfc19acdc6426253f078d78b562c400 -Author: desaivaibhavi -Date: Mon Aug 18 17:46:07 2014 +0530 - - sphinx documentation removed - -diff --git a/webhub/Makefile b/webhub/Makefile -deleted file mode 100644 -index 942b466..0000000 ---- a/webhub/Makefile -+++ /dev/null -@@ -1,177 +0,0 @@ --# Makefile for Sphinx documentation --# -- --# You can set these variables from the command line. --SPHINXOPTS = --SPHINXBUILD = sphinx-build --PAPER = --BUILDDIR = _build -- --# User-friendly check for sphinx-build --ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) --$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) --endif -- --# Internal variables. --PAPEROPT_a4 = -D latex_paper_size=a4 --PAPEROPT_letter = -D latex_paper_size=letter --ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . --# the i18n builder cannot share the environment and doctrees with the others --I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -- --.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext -- --help: -- @echo "Please use \`make ' where is one of" -- @echo " html to make standalone HTML files" -- @echo " dirhtml to make HTML files named index.html in directories" -- @echo " singlehtml to make a single large HTML file" -- @echo " pickle to make pickle files" -- @echo " json to make JSON files" -- @echo " htmlhelp to make HTML files and a HTML help project" -- @echo " qthelp to make HTML files and a qthelp project" -- @echo " devhelp to make HTML files and a Devhelp project" -- @echo " epub to make an epub" -- @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" -- @echo " latexpdf to make LaTeX files and run them through pdflatex" -- @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" -- @echo " text to make text files" -- @echo " man to make manual pages" -- @echo " texinfo to make Texinfo files" -- @echo " info to make Texinfo files and run them through makeinfo" -- @echo " gettext to make PO message catalogs" -- @echo " changes to make an overview of all changed/added/deprecated items" -- @echo " xml to make Docutils-native XML files" -- @echo " pseudoxml to make pseudoxml-XML files for display purposes" -- @echo " linkcheck to check all external links for integrity" -- @echo " doctest to run all doctests embedded in the documentation (if enabled)" -- --clean: -- rm -rf $(BUILDDIR)/* -- --html: -- $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html -- @echo -- @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." -- --dirhtml: -- $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml -- @echo -- @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." -- --singlehtml: -- $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml -- @echo -- @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." -- --pickle: -- $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle -- @echo -- @echo "Build finished; now you can process the pickle files." -- --json: -- $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json -- @echo -- @echo "Build finished; now you can process the JSON files." -- --htmlhelp: -- $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp -- @echo -- @echo "Build finished; now you can run HTML Help Workshop with the" \ -- ".hhp project file in $(BUILDDIR)/htmlhelp." -- --qthelp: -- $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp -- @echo -- @echo "Build finished; now you can run "qcollectiongenerator" with the" \ -- ".qhcp project file in $(BUILDDIR)/qthelp, like this:" -- @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/systerspcweb.qhcp" -- @echo "To view the help file:" -- @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/systerspcweb.qhc" -- --devhelp: -- $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp -- @echo -- @echo "Build finished." -- @echo "To view the help file:" -- @echo "# mkdir -p $$HOME/.local/share/devhelp/systerspcweb" -- @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/systerspcweb" -- @echo "# devhelp" -- --epub: -- $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub -- @echo -- @echo "Build finished. The epub file is in $(BUILDDIR)/epub." -- --latex: -- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex -- @echo -- @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." -- @echo "Run \`make' in that directory to run these through (pdf)latex" \ -- "(use \`make latexpdf' here to do that automatically)." -- --latexpdf: -- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex -- @echo "Running LaTeX files through pdflatex..." -- $(MAKE) -C $(BUILDDIR)/latex all-pdf -- @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." -- --latexpdfja: -- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex -- @echo "Running LaTeX files through platex and dvipdfmx..." -- $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja -- @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." -- --text: -- $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text -- @echo -- @echo "Build finished. The text files are in $(BUILDDIR)/text." -- --man: -- $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man -- @echo -- @echo "Build finished. The manual pages are in $(BUILDDIR)/man." -- --texinfo: -- $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo -- @echo -- @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." -- @echo "Run \`make' in that directory to run these through makeinfo" \ -- "(use \`make info' here to do that automatically)." -- --info: -- $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo -- @echo "Running Texinfo files through makeinfo..." -- make -C $(BUILDDIR)/texinfo info -- @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." -- --gettext: -- $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale -- @echo -- @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." -- --changes: -- $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes -- @echo -- @echo "The overview file is in $(BUILDDIR)/changes." -- --linkcheck: -- $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck -- @echo -- @echo "Link check complete; look for any errors in the above output " \ -- "or in $(BUILDDIR)/linkcheck/output.txt." -- --doctest: -- $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest -- @echo "Testing of doctests in the sources finished, look at the " \ -- "results in $(BUILDDIR)/doctest/output.txt." -- --xml: -- $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml -- @echo -- @echo "Build finished. The XML files are in $(BUILDDIR)/xml." -- --pseudoxml: -- $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml -- @echo -- @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." -diff --git a/webhub/_build/doctrees/environment.pickle b/webhub/_build/doctrees/environment.pickle -deleted file mode 100644 -index 4a369e0..0000000 -Binary files a/webhub/_build/doctrees/environment.pickle and /dev/null differ -diff --git a/webhub/_build/doctrees/systerspcweb.doctree b/webhub/_build/doctrees/systerspcweb.doctree -deleted file mode 100644 -index ec973ac..0000000 -Binary files a/webhub/_build/doctrees/systerspcweb.doctree and /dev/null differ -diff --git a/webhub/_build/html/.buildinfo b/webhub/_build/html/.buildinfo -deleted file mode 100644 -index 564c89b..0000000 ---- a/webhub/_build/html/.buildinfo -+++ /dev/null -@@ -1,4 +0,0 @@ --# Sphinx build info version 1 --# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. --config: badb373ed0d498a883c1ed6b8d08ef26 --tags: 645f666f9bcd5a90fca523b33c5a78b7 -diff --git a/webhub/_build/html/_sources/systerspcweb.txt b/webhub/_build/html/_sources/systerspcweb.txt -deleted file mode 100644 -index 01325ed..0000000 ---- a/webhub/_build/html/_sources/systerspcweb.txt -+++ /dev/null -@@ -1,26 +0,0 @@ --.. systerspcweb documentation master file, created by -- sphinx-quickstart on Wed Aug 13 20:07:49 2014. -- You can adapt this file completely to your liking, but it should at least -- contain the root `toctree` directive. -- --Welcome to systerspcweb's documentation! --======================================== -- --Contents: -- --.. toctree:: -- :maxdepth: 2 -- --.. automodule:: serializers.py -- --.. autoclass:: UserSerializer -- :members: -- -- --Indices and tables --================== -- --* :ref:`genindex` --* :ref:`modindex` --* :ref:`search` -- -diff --git a/webhub/_build/html/_static/ajax-loader.gif b/webhub/_build/html/_static/ajax-loader.gif -deleted file mode 100644 -index 61faf8c..0000000 -Binary files a/webhub/_build/html/_static/ajax-loader.gif and /dev/null differ -diff --git a/webhub/_build/html/_static/basic.css b/webhub/_build/html/_static/basic.css -deleted file mode 100644 -index 967e36c..0000000 ---- a/webhub/_build/html/_static/basic.css -+++ /dev/null -@@ -1,537 +0,0 @@ --/* -- * basic.css -- * ~~~~~~~~~ -- * -- * Sphinx stylesheet -- basic theme. -- * -- * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. -- * :license: BSD, see LICENSE for details. -- * -- */ -- --/* -- main layout ----------------------------------------------------------- */ -- --div.clearer { -- clear: both; --} -- --/* -- relbar ---------------------------------------------------------------- */ -- --div.related { -- width: 100%; -- font-size: 90%; --} -- --div.related h3 { -- display: none; --} -- --div.related ul { -- margin: 0; -- padding: 0 0 0 10px; -- list-style: none; --} -- --div.related li { -- display: inline; --} -- --div.related li.right { -- float: right; -- margin-right: 5px; --} -- --/* -- sidebar --------------------------------------------------------------- */ -- --div.sphinxsidebarwrapper { -- padding: 10px 5px 0 10px; --} -- --div.sphinxsidebar { -- float: left; -- width: 230px; -- margin-left: -100%; -- font-size: 90%; --} -- --div.sphinxsidebar ul { -- list-style: none; --} -- --div.sphinxsidebar ul ul, --div.sphinxsidebar ul.want-points { -- margin-left: 20px; -- list-style: square; --} -- --div.sphinxsidebar ul ul { -- margin-top: 0; -- margin-bottom: 0; --} -- --div.sphinxsidebar form { -- margin-top: 10px; --} -- --div.sphinxsidebar input { -- border: 1px solid #98dbcc; -- font-family: sans-serif; -- font-size: 1em; --} -- --div.sphinxsidebar #searchbox input[type="text"] { -- width: 170px; --} -- --div.sphinxsidebar #searchbox input[type="submit"] { -- width: 30px; --} -- --img { -- border: 0; -- max-width: 100%; --} -- --/* -- search page ----------------------------------------------------------- */ -- --ul.search { -- margin: 10px 0 0 20px; -- padding: 0; --} -- --ul.search li { -- padding: 5px 0 5px 20px; -- background-image: url(file.png); -- background-repeat: no-repeat; -- background-position: 0 7px; --} -- --ul.search li a { -- font-weight: bold; --} -- --ul.search li div.context { -- color: #888; -- margin: 2px 0 0 30px; -- text-align: left; --} -- --ul.keywordmatches li.goodmatch a { -- font-weight: bold; --} -- --/* -- index page ------------------------------------------------------------ */ -- --table.contentstable { -- width: 90%; --} -- --table.contentstable p.biglink { -- line-height: 150%; --} -- --a.biglink { -- font-size: 1.3em; --} -- --span.linkdescr { -- font-style: italic; -- padding-top: 5px; -- font-size: 90%; --} -- --/* -- general index --------------------------------------------------------- */ -- --table.indextable { -- width: 100%; --} -- --table.indextable td { -- text-align: left; -- vertical-align: top; --} -- --table.indextable dl, table.indextable dd { -- margin-top: 0; -- margin-bottom: 0; --} -- --table.indextable tr.pcap { -- height: 10px; --} -- --table.indextable tr.cap { -- margin-top: 10px; -- background-color: #f2f2f2; --} -- --img.toggler { -- margin-right: 3px; -- margin-top: 3px; -- cursor: pointer; --} -- --div.modindex-jumpbox { -- border-top: 1px solid #ddd; -- border-bottom: 1px solid #ddd; -- margin: 1em 0 1em 0; -- padding: 0.4em; --} -- --div.genindex-jumpbox { -- border-top: 1px solid #ddd; -- border-bottom: 1px solid #ddd; -- margin: 1em 0 1em 0; -- padding: 0.4em; --} -- --/* -- general body styles --------------------------------------------------- */ -- --a.headerlink { -- visibility: hidden; --} -- --h1:hover > a.headerlink, --h2:hover > a.headerlink, --h3:hover > a.headerlink, --h4:hover > a.headerlink, --h5:hover > a.headerlink, --h6:hover > a.headerlink, --dt:hover > a.headerlink { -- visibility: visible; --} -- --div.body p.caption { -- text-align: inherit; --} -- --div.body td { -- text-align: left; --} -- --.field-list ul { -- padding-left: 1em; --} -- --.first { -- margin-top: 0 !important; --} -- --p.rubric { -- margin-top: 30px; -- font-weight: bold; --} -- --img.align-left, .figure.align-left, object.align-left { -- clear: left; -- float: left; -- margin-right: 1em; --} -- --img.align-right, .figure.align-right, object.align-right { -- clear: right; -- float: right; -- margin-left: 1em; --} -- --img.align-center, .figure.align-center, object.align-center { -- display: block; -- margin-left: auto; -- margin-right: auto; --} -- --.align-left { -- text-align: left; --} -- --.align-center { -- text-align: center; --} -- --.align-right { -- text-align: right; --} -- --/* -- sidebars -------------------------------------------------------------- */ -- --div.sidebar { -- margin: 0 0 0.5em 1em; -- border: 1px solid #ddb; -- padding: 7px 7px 0 7px; -- background-color: #ffe; -- width: 40%; -- float: right; --} -- --p.sidebar-title { -- font-weight: bold; --} -- --/* -- topics ---------------------------------------------------------------- */ -- --div.topic { -- border: 1px solid #ccc; -- padding: 7px 7px 0 7px; -- margin: 10px 0 10px 0; --} -- --p.topic-title { -- font-size: 1.1em; -- font-weight: bold; -- margin-top: 10px; --} -- --/* -- admonitions ----------------------------------------------------------- */ -- --div.admonition { -- margin-top: 10px; -- margin-bottom: 10px; -- padding: 7px; --} -- --div.admonition dt { -- font-weight: bold; --} -- --div.admonition dl { -- margin-bottom: 0; --} -- --p.admonition-title { -- margin: 0px 10px 5px 0px; -- font-weight: bold; --} -- --div.body p.centered { -- text-align: center; -- margin-top: 25px; --} -- --/* -- tables ---------------------------------------------------------------- */ -- --table.docutils { -- border: 0; -- border-collapse: collapse; --} -- --table.docutils td, table.docutils th { -- padding: 1px 8px 1px 5px; -- border-top: 0; -- border-left: 0; -- border-right: 0; -- border-bottom: 1px solid #aaa; --} -- --table.field-list td, table.field-list th { -- border: 0 !important; --} -- --table.footnote td, table.footnote th { -- border: 0 !important; --} -- --th { -- text-align: left; -- padding-right: 5px; --} -- --table.citation { -- border-left: solid 1px gray; -- margin-left: 1px; --} -- --table.citation td { -- border-bottom: none; --} -- --/* -- other body styles ----------------------------------------------------- */ -- --ol.arabic { -- list-style: decimal; --} -- --ol.loweralpha { -- list-style: lower-alpha; --} -- --ol.upperalpha { -- list-style: upper-alpha; --} -- --ol.lowerroman { -- list-style: lower-roman; --} -- --ol.upperroman { -- list-style: upper-roman; --} -- --dl { -- margin-bottom: 15px; --} -- --dd p { -- margin-top: 0px; --} -- --dd ul, dd table { -- margin-bottom: 10px; --} -- --dd { -- margin-top: 3px; -- margin-bottom: 10px; -- margin-left: 30px; --} -- --dt:target, .highlighted { -- background-color: #fbe54e; --} -- --dl.glossary dt { -- font-weight: bold; -- font-size: 1.1em; --} -- --.field-list ul { -- margin: 0; -- padding-left: 1em; --} -- --.field-list p { -- margin: 0; --} -- --.optional { -- font-size: 1.3em; --} -- --.versionmodified { -- font-style: italic; --} -- --.system-message { -- background-color: #fda; -- padding: 5px; -- border: 3px solid red; --} -- --.footnote:target { -- background-color: #ffa; --} -- --.line-block { -- display: block; -- margin-top: 1em; -- margin-bottom: 1em; --} -- --.line-block .line-block { -- margin-top: 0; -- margin-bottom: 0; -- margin-left: 1.5em; --} -- --.guilabel, .menuselection { -- font-family: sans-serif; --} -- --.accelerator { -- text-decoration: underline; --} -- --.classifier { -- font-style: oblique; --} -- --abbr, acronym { -- border-bottom: dotted 1px; -- cursor: help; --} -- --/* -- code displays --------------------------------------------------------- */ -- --pre { -- overflow: auto; -- overflow-y: hidden; /* fixes display issues on Chrome browsers */ --} -- --td.linenos pre { -- padding: 5px 0px; -- border: 0; -- background-color: transparent; -- color: #aaa; --} -- --table.highlighttable { -- margin-left: 0.5em; --} -- --table.highlighttable td { -- padding: 0 0.5em 0 0.5em; --} -- --tt.descname { -- background-color: transparent; -- font-weight: bold; -- font-size: 1.2em; --} -- --tt.descclassname { -- background-color: transparent; --} -- --tt.xref, a tt { -- background-color: transparent; -- font-weight: bold; --} -- --h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { -- background-color: transparent; --} -- --.viewcode-link { -- float: right; --} -- --.viewcode-back { -- float: right; -- font-family: sans-serif; --} -- --div.viewcode-block:target { -- margin: -1px -10px; -- padding: 0 10px; --} -- --/* -- math display ---------------------------------------------------------- */ -- --img.math { -- vertical-align: middle; --} -- --div.body div.math p { -- text-align: center; --} -- --span.eqno { -- float: right; --} -- --/* -- printout stylesheet --------------------------------------------------- */ -- --@media print { -- div.document, -- div.documentwrapper, -- div.bodywrapper { -- margin: 0 !important; -- width: 100%; -- } -- -- div.sphinxsidebar, -- div.related, -- div.footer, -- #top-link { -- display: none; -- } --} -\ No newline at end of file -diff --git a/webhub/_build/html/_static/comment-bright.png b/webhub/_build/html/_static/comment-bright.png -deleted file mode 100644 -index 551517b..0000000 -Binary files a/webhub/_build/html/_static/comment-bright.png and /dev/null differ -diff --git a/webhub/_build/html/_static/comment-close.png b/webhub/_build/html/_static/comment-close.png -deleted file mode 100644 -index 09b54be..0000000 -Binary files a/webhub/_build/html/_static/comment-close.png and /dev/null differ -diff --git a/webhub/_build/html/_static/comment.png b/webhub/_build/html/_static/comment.png -deleted file mode 100644 -index 92feb52..0000000 -Binary files a/webhub/_build/html/_static/comment.png and /dev/null differ -diff --git a/webhub/_build/html/_static/default.css b/webhub/_build/html/_static/default.css -deleted file mode 100644 -index 5f1399a..0000000 ---- a/webhub/_build/html/_static/default.css -+++ /dev/null -@@ -1,256 +0,0 @@ --/* -- * default.css_t -- * ~~~~~~~~~~~~~ -- * -- * Sphinx stylesheet -- default theme. -- * -- * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. -- * :license: BSD, see LICENSE for details. -- * -- */ -- --@import url("basic.css"); -- --/* -- page layout ----------------------------------------------------------- */ -- --body { -- font-family: sans-serif; -- font-size: 100%; -- background-color: #11303d; -- color: #000; -- margin: 0; -- padding: 0; --} -- --div.document { -- background-color: #1c4e63; --} -- --div.documentwrapper { -- float: left; -- width: 100%; --} -- --div.bodywrapper { -- margin: 0 0 0 230px; --} -- --div.body { -- background-color: #ffffff; -- color: #000000; -- padding: 0 20px 30px 20px; --} -- --div.footer { -- color: #ffffff; -- width: 100%; -- padding: 9px 0 9px 0; -- text-align: center; -- font-size: 75%; --} -- --div.footer a { -- color: #ffffff; -- text-decoration: underline; --} -- --div.related { -- background-color: #133f52; -- line-height: 30px; -- color: #ffffff; --} -- --div.related a { -- color: #ffffff; --} -- --div.sphinxsidebar { --} -- --div.sphinxsidebar h3 { -- font-family: 'Trebuchet MS', sans-serif; -- color: #ffffff; -- font-size: 1.4em; -- font-weight: normal; -- margin: 0; -- padding: 0; --} -- --div.sphinxsidebar h3 a { -- color: #ffffff; --} -- --div.sphinxsidebar h4 { -- font-family: 'Trebuchet MS', sans-serif; -- color: #ffffff; -- font-size: 1.3em; -- font-weight: normal; -- margin: 5px 0 0 0; -- padding: 0; --} -- --div.sphinxsidebar p { -- color: #ffffff; --} -- --div.sphinxsidebar p.topless { -- margin: 5px 10px 10px 10px; --} -- --div.sphinxsidebar ul { -- margin: 10px; -- padding: 0; -- color: #ffffff; --} -- --div.sphinxsidebar a { -- color: #98dbcc; --} -- --div.sphinxsidebar input { -- border: 1px solid #98dbcc; -- font-family: sans-serif; -- font-size: 1em; --} -- -- -- --/* -- hyperlink styles ------------------------------------------------------ */ -- --a { -- color: #355f7c; -- text-decoration: none; --} -- --a:visited { -- color: #355f7c; -- text-decoration: none; --} -- --a:hover { -- text-decoration: underline; --} -- -- -- --/* -- body styles ----------------------------------------------------------- */ -- --div.body h1, --div.body h2, --div.body h3, --div.body h4, --div.body h5, --div.body h6 { -- font-family: 'Trebuchet MS', sans-serif; -- background-color: #f2f2f2; -- font-weight: normal; -- color: #20435c; -- border-bottom: 1px solid #ccc; -- margin: 20px -20px 10px -20px; -- padding: 3px 0 3px 10px; --} -- --div.body h1 { margin-top: 0; font-size: 200%; } --div.body h2 { font-size: 160%; } --div.body h3 { font-size: 140%; } --div.body h4 { font-size: 120%; } --div.body h5 { font-size: 110%; } --div.body h6 { font-size: 100%; } -- --a.headerlink { -- color: #c60f0f; -- font-size: 0.8em; -- padding: 0 4px 0 4px; -- text-decoration: none; --} -- --a.headerlink:hover { -- background-color: #c60f0f; -- color: white; --} -- --div.body p, div.body dd, div.body li { -- text-align: justify; -- line-height: 130%; --} -- --div.admonition p.admonition-title + p { -- display: inline; --} -- --div.admonition p { -- margin-bottom: 5px; --} -- --div.admonition pre { -- margin-bottom: 5px; --} -- --div.admonition ul, div.admonition ol { -- margin-bottom: 5px; --} -- --div.note { -- background-color: #eee; -- border: 1px solid #ccc; --} -- --div.seealso { -- background-color: #ffc; -- border: 1px solid #ff6; --} -- --div.topic { -- background-color: #eee; --} -- --div.warning { -- background-color: #ffe4e4; -- border: 1px solid #f66; --} -- --p.admonition-title { -- display: inline; --} -- --p.admonition-title:after { -- content: ":"; --} -- --pre { -- padding: 5px; -- background-color: #eeffcc; -- color: #333333; -- line-height: 120%; -- border: 1px solid #ac9; -- border-left: none; -- border-right: none; --} -- --tt { -- background-color: #ecf0f3; -- padding: 0 1px 0 1px; -- font-size: 0.95em; --} -- --th { -- background-color: #ede; --} -- --.warning tt { -- background: #efc2c2; --} -- --.note tt { -- background: #d6d6d6; --} -- --.viewcode-back { -- font-family: sans-serif; --} -- --div.viewcode-block:target { -- background-color: #f4debf; -- border-top: 1px solid #ac9; -- border-bottom: 1px solid #ac9; --} -\ No newline at end of file -diff --git a/webhub/_build/html/_static/doctools.js b/webhub/_build/html/_static/doctools.js -deleted file mode 100644 -index c5455c9..0000000 ---- a/webhub/_build/html/_static/doctools.js -+++ /dev/null -@@ -1,238 +0,0 @@ --/* -- * doctools.js -- * ~~~~~~~~~~~ -- * -- * Sphinx JavaScript utilities for all documentation. -- * -- * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. -- * :license: BSD, see LICENSE for details. -- * -- */ -- --/** -- * select a different prefix for underscore -- */ --$u = _.noConflict(); -- --/** -- * make the code below compatible with browsers without -- * an installed firebug like debugger --if (!window.console || !console.firebug) { -- var names = ["log", "debug", "info", "warn", "error", "assert", "dir", -- "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", -- "profile", "profileEnd"]; -- window.console = {}; -- for (var i = 0; i < names.length; ++i) -- window.console[names[i]] = function() {}; --} -- */ -- --/** -- * small helper function to urldecode strings -- */ --jQuery.urldecode = function(x) { -- return decodeURIComponent(x).replace(/\+/g, ' '); --}; -- --/** -- * small helper function to urlencode strings -- */ --jQuery.urlencode = encodeURIComponent; -- --/** -- * This function returns the parsed url parameters of the -- * current request. Multiple values per key are supported, -- * it will always return arrays of strings for the value parts. -- */ --jQuery.getQueryParameters = function(s) { -- if (typeof s == 'undefined') -- s = document.location.search; -- var parts = s.substr(s.indexOf('?') + 1).split('&'); -- var result = {}; -- for (var i = 0; i < parts.length; i++) { -- var tmp = parts[i].split('=', 2); -- var key = jQuery.urldecode(tmp[0]); -- var value = jQuery.urldecode(tmp[1]); -- if (key in result) -- result[key].push(value); -- else -- result[key] = [value]; -- } -- return result; --}; -- --/** -- * highlight a given string on a jquery object by wrapping it in -- * span elements with the given class name. -- */ --jQuery.fn.highlightText = function(text, className) { -- function highlight(node) { -- if (node.nodeType == 3) { -- var val = node.nodeValue; -- var pos = val.toLowerCase().indexOf(text); -- if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { -- var span = document.createElement("span"); -- span.className = className; -- span.appendChild(document.createTextNode(val.substr(pos, text.length))); -- node.parentNode.insertBefore(span, node.parentNode.insertBefore( -- document.createTextNode(val.substr(pos + text.length)), -- node.nextSibling)); -- node.nodeValue = val.substr(0, pos); -- } -- } -- else if (!jQuery(node).is("button, select, textarea")) { -- jQuery.each(node.childNodes, function() { -- highlight(this); -- }); -- } -- } -- return this.each(function() { -- highlight(this); -- }); --}; -- --/** -- * Small JavaScript module for the documentation. -- */ --var Documentation = { -- -- init : function() { -- this.fixFirefoxAnchorBug(); -- this.highlightSearchWords(); -- this.initIndexTable(); -- }, -- -- /** -- * i18n support -- */ -- TRANSLATIONS : {}, -- PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, -- LOCALE : 'unknown', -- -- // gettext and ngettext don't access this so that the functions -- // can safely bound to a different name (_ = Documentation.gettext) -- gettext : function(string) { -- var translated = Documentation.TRANSLATIONS[string]; -- if (typeof translated == 'undefined') -- return string; -- return (typeof translated == 'string') ? translated : translated[0]; -- }, -- -- ngettext : function(singular, plural, n) { -- var translated = Documentation.TRANSLATIONS[singular]; -- if (typeof translated == 'undefined') -- return (n == 1) ? singular : plural; -- return translated[Documentation.PLURALEXPR(n)]; -- }, -- -- addTranslations : function(catalog) { -- for (var key in catalog.messages) -- this.TRANSLATIONS[key] = catalog.messages[key]; -- this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); -- this.LOCALE = catalog.locale; -- }, -- -- /** -- * add context elements like header anchor links -- */ -- addContextElements : function() { -- $('div[id] > :header:first').each(function() { -- $('\u00B6'). -- attr('href', '#' + this.id). -- attr('title', _('Permalink to this headline')). -- appendTo(this); -- }); -- $('dt[id]').each(function() { -- $('\u00B6'). -- attr('href', '#' + this.id). -- attr('title', _('Permalink to this definition')). -- appendTo(this); -- }); -- }, -- -- /** -- * workaround a firefox stupidity -- */ -- fixFirefoxAnchorBug : function() { -- if (document.location.hash && $.browser.mozilla) -- window.setTimeout(function() { -- document.location.href += ''; -- }, 10); -- }, -- -- /** -- * highlight the search words provided in the url in the text -- */ -- highlightSearchWords : function() { -- var params = $.getQueryParameters(); -- var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; -- if (terms.length) { -- var body = $('div.body'); -- if (!body.length) { -- body = $('body'); -- } -- window.setTimeout(function() { -- $.each(terms, function() { -- body.highlightText(this.toLowerCase(), 'highlighted'); -- }); -- }, 10); -- $('') -- .appendTo($('#searchbox')); -- } -- }, -- -- /** -- * init the domain index toggle buttons -- */ -- initIndexTable : function() { -- var togglers = $('img.toggler').click(function() { -- var src = $(this).attr('src'); -- var idnum = $(this).attr('id').substr(7); -- $('tr.cg-' + idnum).toggle(); -- if (src.substr(-9) == 'minus.png') -- $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); -- else -- $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); -- }).css('display', ''); -- if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { -- togglers.click(); -- } -- }, -- -- /** -- * helper function to hide the search marks again -- */ -- hideSearchWords : function() { -- $('#searchbox .highlight-link').fadeOut(300); -- $('span.highlighted').removeClass('highlighted'); -- }, -- -- /** -- * make the url absolute -- */ -- makeURL : function(relativeURL) { -- return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; -- }, -- -- /** -- * get the current relative url -- */ -- getCurrentURL : function() { -- var path = document.location.pathname; -- var parts = path.split(/\//); -- $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { -- if (this == '..') -- parts.pop(); -- }); -- var url = parts.join('/'); -- return path.substring(url.lastIndexOf('/') + 1, path.length - 1); -- } --}; -- --// quick alias for translations --_ = Documentation.gettext; -- --$(document).ready(function() { -- Documentation.init(); --}); -diff --git a/webhub/_build/html/_static/down-pressed.png b/webhub/_build/html/_static/down-pressed.png -deleted file mode 100644 -index 6f7ad78..0000000 -Binary files a/webhub/_build/html/_static/down-pressed.png and /dev/null differ -diff --git a/webhub/_build/html/_static/down.png b/webhub/_build/html/_static/down.png -deleted file mode 100644 -index 3003a88..0000000 -Binary files a/webhub/_build/html/_static/down.png and /dev/null differ -diff --git a/webhub/_build/html/_static/file.png b/webhub/_build/html/_static/file.png -deleted file mode 100644 -index d18082e..0000000 -Binary files a/webhub/_build/html/_static/file.png and /dev/null differ -diff --git a/webhub/_build/html/_static/jquery.js b/webhub/_build/html/_static/jquery.js -deleted file mode 100644 -index e2efc33..0000000 ---- a/webhub/_build/html/_static/jquery.js -+++ /dev/null -@@ -1,9404 +0,0 @@ --/*! -- * jQuery JavaScript Library v1.7.2 -- * http://jquery.com/ -- * -- * Copyright 2011, John Resig -- * Dual licensed under the MIT or GPL Version 2 licenses. -- * http://jquery.org/license -- * -- * Includes Sizzle.js -- * http://sizzlejs.com/ -- * Copyright 2011, The Dojo Foundation -- * Released under the MIT, BSD, and GPL Licenses. -- * -- * Date: Fri Jul 5 14:07:58 UTC 2013 -- */ --(function( window, undefined ) { -- --// Use the correct document accordingly with window argument (sandbox) --var document = window.document, -- navigator = window.navigator, -- location = window.location; --var jQuery = (function() { -- --// Define a local copy of jQuery --var jQuery = function( selector, context ) { -- // The jQuery object is actually just the init constructor 'enhanced' -- return new jQuery.fn.init( selector, context, rootjQuery ); -- }, -- -- // Map over jQuery in case of overwrite -- _jQuery = window.jQuery, -- -- // Map over the $ in case of overwrite -- _$ = window.$, -- -- // A central reference to the root jQuery(document) -- rootjQuery, -- -- // A simple way to check for HTML strings or ID strings -- // Prioritize #id over to avoid XSS via location.hash (#9521) -- quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, -- -- // Check if a string has a non-whitespace character in it -- rnotwhite = /\S/, -- -- // Used for trimming whitespace -- trimLeft = /^\s+/, -- trimRight = /\s+$/, -- -- // Match a standalone tag -- rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, -- -- // JSON RegExp -- rvalidchars = /^[\],:{}\s]*$/, -- rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, -- rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, -- rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, -- -- // Useragent RegExp -- rwebkit = /(webkit)[ \/]([\w.]+)/, -- ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, -- rmsie = /(msie) ([\w.]+)/, -- rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, -- -- // Matches dashed string for camelizing -- rdashAlpha = /-([a-z]|[0-9])/ig, -- rmsPrefix = /^-ms-/, -- -- // Used by jQuery.camelCase as callback to replace() -- fcamelCase = function( all, letter ) { -- return ( letter + "" ).toUpperCase(); -- }, -- -- // Keep a UserAgent string for use with jQuery.browser -- userAgent = navigator.userAgent, -- -- // For matching the engine and version of the browser -- browserMatch, -- -- // The deferred used on DOM ready -- readyList, -- -- // The ready event handler -- DOMContentLoaded, -- -- // Save a reference to some core methods -- toString = Object.prototype.toString, -- hasOwn = Object.prototype.hasOwnProperty, -- push = Array.prototype.push, -- slice = Array.prototype.slice, -- trim = String.prototype.trim, -- indexOf = Array.prototype.indexOf, -- -- // [[Class]] -> type pairs -- class2type = {}; -- --jQuery.fn = jQuery.prototype = { -- constructor: jQuery, -- init: function( selector, context, rootjQuery ) { -- var match, elem, ret, doc; -- -- // Handle $(""), $(null), or $(undefined) -- if ( !selector ) { -- return this; -- } -- -- // Handle $(DOMElement) -- if ( selector.nodeType ) { -- this.context = this[0] = selector; -- this.length = 1; -- return this; -- } -- -- // The body element only exists once, optimize finding it -- if ( selector === "body" && !context && document.body ) { -- this.context = document; -- this[0] = document.body; -- this.selector = selector; -- this.length = 1; -- return this; -- } -- -- // Handle HTML strings -- if ( typeof selector === "string" ) { -- // Are we dealing with HTML string or an ID? -- if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { -- // Assume that strings that start and end with <> are HTML and skip the regex check -- match = [ null, selector, null ]; -- -- } else { -- match = quickExpr.exec( selector ); -- } -- -- // Verify a match, and that no context was specified for #id -- if ( match && (match[1] || !context) ) { -- -- // HANDLE: $(html) -> $(array) -- if ( match[1] ) { -- context = context instanceof jQuery ? context[0] : context; -- doc = ( context ? context.ownerDocument || context : document ); -- -- // If a single string is passed in and it's a single tag -- // just do a createElement and skip the rest -- ret = rsingleTag.exec( selector ); -- -- if ( ret ) { -- if ( jQuery.isPlainObject( context ) ) { -- selector = [ document.createElement( ret[1] ) ]; -- jQuery.fn.attr.call( selector, context, true ); -- -- } else { -- selector = [ doc.createElement( ret[1] ) ]; -- } -- -- } else { -- ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); -- selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes; -- } -- -- return jQuery.merge( this, selector ); -- -- // HANDLE: $("#id") -- } else { -- elem = document.getElementById( match[2] ); -- -- // Check parentNode to catch when Blackberry 4.6 returns -- // nodes that are no longer in the document #6963 -- if ( elem && elem.parentNode ) { -- // Handle the case where IE and Opera return items -- // by name instead of ID -- if ( elem.id !== match[2] ) { -- return rootjQuery.find( selector ); -- } -- -- // Otherwise, we inject the element directly into the jQuery object -- this.length = 1; -- this[0] = elem; -- } -- -- this.context = document; -- this.selector = selector; -- return this; -- } -- -- // HANDLE: $(expr, $(...)) -- } else if ( !context || context.jquery ) { -- return ( context || rootjQuery ).find( selector ); -- -- // HANDLE: $(expr, context) -- // (which is just equivalent to: $(context).find(expr) -- } else { -- return this.constructor( context ).find( selector ); -- } -- -- // HANDLE: $(function) -- // Shortcut for document ready -- } else if ( jQuery.isFunction( selector ) ) { -- return rootjQuery.ready( selector ); -- } -- -- if ( selector.selector !== undefined ) { -- this.selector = selector.selector; -- this.context = selector.context; -- } -- -- return jQuery.makeArray( selector, this ); -- }, -- -- // Start with an empty selector -- selector: "", -- -- // The current version of jQuery being used -- jquery: "1.7.2", -- -- // The default length of a jQuery object is 0 -- length: 0, -- -- // The number of elements contained in the matched element set -- size: function() { -- return this.length; -- }, -- -- toArray: function() { -- return slice.call( this, 0 ); -- }, -- -- // Get the Nth element in the matched element set OR -- // Get the whole matched element set as a clean array -- get: function( num ) { -- return num == null ? -- -- // Return a 'clean' array -- this.toArray() : -- -- // Return just the object -- ( num < 0 ? this[ this.length + num ] : this[ num ] ); -- }, -- -- // Take an array of elements and push it onto the stack -- // (returning the new matched element set) -- pushStack: function( elems, name, selector ) { -- // Build a new jQuery matched element set -- var ret = this.constructor(); -- -- if ( jQuery.isArray( elems ) ) { -- push.apply( ret, elems ); -- -- } else { -- jQuery.merge( ret, elems ); -- } -- -- // Add the old object onto the stack (as a reference) -- ret.prevObject = this; -- -- ret.context = this.context; -- -- if ( name === "find" ) { -- ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; -- } else if ( name ) { -- ret.selector = this.selector + "." + name + "(" + selector + ")"; -- } -- -- // Return the newly-formed element set -- return ret; -- }, -- -- // Execute a callback for every element in the matched set. -- // (You can seed the arguments with an array of args, but this is -- // only used internally.) -- each: function( callback, args ) { -- return jQuery.each( this, callback, args ); -- }, -- -- ready: function( fn ) { -- // Attach the listeners -- jQuery.bindReady(); -- -- // Add the callback -- readyList.add( fn ); -- -- return this; -- }, -- -- eq: function( i ) { -- i = +i; -- return i === -1 ? -- this.slice( i ) : -- this.slice( i, i + 1 ); -- }, -- -- first: function() { -- return this.eq( 0 ); -- }, -- -- last: function() { -- return this.eq( -1 ); -- }, -- -- slice: function() { -- return this.pushStack( slice.apply( this, arguments ), -- "slice", slice.call(arguments).join(",") ); -- }, -- -- map: function( callback ) { -- return this.pushStack( jQuery.map(this, function( elem, i ) { -- return callback.call( elem, i, elem ); -- })); -- }, -- -- end: function() { -- return this.prevObject || this.constructor(null); -- }, -- -- // For internal use only. -- // Behaves like an Array's method, not like a jQuery method. -- push: push, -- sort: [].sort, -- splice: [].splice --}; -- --// Give the init function the jQuery prototype for later instantiation --jQuery.fn.init.prototype = jQuery.fn; -- --jQuery.extend = jQuery.fn.extend = function() { -- var options, name, src, copy, copyIsArray, clone, -- target = arguments[0] || {}, -- i = 1, -- length = arguments.length, -- deep = false; -- -- // Handle a deep copy situation -- if ( typeof target === "boolean" ) { -- deep = target; -- target = arguments[1] || {}; -- // skip the boolean and the target -- i = 2; -- } -- -- // Handle case when target is a string or something (possible in deep copy) -- if ( typeof target !== "object" && !jQuery.isFunction(target) ) { -- target = {}; -- } -- -- // extend jQuery itself if only one argument is passed -- if ( length === i ) { -- target = this; -- --i; -- } -- -- for ( ; i < length; i++ ) { -- // Only deal with non-null/undefined values -- if ( (options = arguments[ i ]) != null ) { -- // Extend the base object -- for ( name in options ) { -- src = target[ name ]; -- copy = options[ name ]; -- -- // Prevent never-ending loop -- if ( target === copy ) { -- continue; -- } -- -- // Recurse if we're merging plain objects or arrays -- if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { -- if ( copyIsArray ) { -- copyIsArray = false; -- clone = src && jQuery.isArray(src) ? src : []; -- -- } else { -- clone = src && jQuery.isPlainObject(src) ? src : {}; -- } -- -- // Never move original objects, clone them -- target[ name ] = jQuery.extend( deep, clone, copy ); -- -- // Don't bring in undefined values -- } else if ( copy !== undefined ) { -- target[ name ] = copy; -- } -- } -- } -- } -- -- // Return the modified object -- return target; --}; -- --jQuery.extend({ -- noConflict: function( deep ) { -- if ( window.$ === jQuery ) { -- window.$ = _$; -- } -- -- if ( deep && window.jQuery === jQuery ) { -- window.jQuery = _jQuery; -- } -- -- return jQuery; -- }, -- -- // Is the DOM ready to be used? Set to true once it occurs. -- isReady: false, -- -- // A counter to track how many items to wait for before -- // the ready event fires. See #6781 -- readyWait: 1, -- -- // Hold (or release) the ready event -- holdReady: function( hold ) { -- if ( hold ) { -- jQuery.readyWait++; -- } else { -- jQuery.ready( true ); -- } -- }, -- -- // Handle when the DOM is ready -- ready: function( wait ) { -- // Either a released hold or an DOMready/load event and not yet ready -- if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { -- // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). -- if ( !document.body ) { -- return setTimeout( jQuery.ready, 1 ); -- } -- -- // Remember that the DOM is ready -- jQuery.isReady = true; -- -- // If a normal DOM Ready event fired, decrement, and wait if need be -- if ( wait !== true && --jQuery.readyWait > 0 ) { -- return; -- } -- -- // If there are functions bound, to execute -- readyList.fireWith( document, [ jQuery ] ); -- -- // Trigger any bound ready events -- if ( jQuery.fn.trigger ) { -- jQuery( document ).trigger( "ready" ).off( "ready" ); -- } -- } -- }, -- -- bindReady: function() { -- if ( readyList ) { -- return; -- } -- -- readyList = jQuery.Callbacks( "once memory" ); -- -- // Catch cases where $(document).ready() is called after the -- // browser event has already occurred. -- if ( document.readyState === "complete" ) { -- // Handle it asynchronously to allow scripts the opportunity to delay ready -- return setTimeout( jQuery.ready, 1 ); -- } -- -- // Mozilla, Opera and webkit nightlies currently support this event -- if ( document.addEventListener ) { -- // Use the handy event callback -- document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); -- -- // A fallback to window.onload, that will always work -- window.addEventListener( "load", jQuery.ready, false ); -- -- // If IE event model is used -- } else if ( document.attachEvent ) { -- // ensure firing before onload, -- // maybe late but safe also for iframes -- document.attachEvent( "onreadystatechange", DOMContentLoaded ); -- -- // A fallback to window.onload, that will always work -- window.attachEvent( "onload", jQuery.ready ); -- -- // If IE and not a frame -- // continually check to see if the document is ready -- var toplevel = false; -- -- try { -- toplevel = window.frameElement == null; -- } catch(e) {} -- -- if ( document.documentElement.doScroll && toplevel ) { -- doScrollCheck(); -- } -- } -- }, -- -- // See test/unit/core.js for details concerning isFunction. -- // Since version 1.3, DOM methods and functions like alert -- // aren't supported. They return false on IE (#2968). -- isFunction: function( obj ) { -- return jQuery.type(obj) === "function"; -- }, -- -- isArray: Array.isArray || function( obj ) { -- return jQuery.type(obj) === "array"; -- }, -- -- isWindow: function( obj ) { -- return obj != null && obj == obj.window; -- }, -- -- isNumeric: function( obj ) { -- return !isNaN( parseFloat(obj) ) && isFinite( obj ); -- }, -- -- type: function( obj ) { -- return obj == null ? -- String( obj ) : -- class2type[ toString.call(obj) ] || "object"; -- }, -- -- isPlainObject: function( obj ) { -- // Must be an Object. -- // Because of IE, we also have to check the presence of the constructor property. -- // Make sure that DOM nodes and window objects don't pass through, as well -- if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { -- return false; -- } -- -- try { -- // Not own constructor property must be Object -- if ( obj.constructor && -- !hasOwn.call(obj, "constructor") && -- !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { -- return false; -- } -- } catch ( e ) { -- // IE8,9 Will throw exceptions on certain host objects #9897 -- return false; -- } -- -- // Own properties are enumerated firstly, so to speed up, -- // if last one is own, then all properties are own. -- -- var key; -- for ( key in obj ) {} -- -- return key === undefined || hasOwn.call( obj, key ); -- }, -- -- isEmptyObject: function( obj ) { -- for ( var name in obj ) { -- return false; -- } -- return true; -- }, -- -- error: function( msg ) { -- throw new Error( msg ); -- }, -- -- parseJSON: function( data ) { -- if ( typeof data !== "string" || !data ) { -- return null; -- } -- -- // Make sure leading/trailing whitespace is removed (IE can't handle it) -- data = jQuery.trim( data ); -- -- // Attempt to parse using the native JSON parser first -- if ( window.JSON && window.JSON.parse ) { -- return window.JSON.parse( data ); -- } -- -- // Make sure the incoming data is actual JSON -- // Logic borrowed from http://json.org/json2.js -- if ( rvalidchars.test( data.replace( rvalidescape, "@" ) -- .replace( rvalidtokens, "]" ) -- .replace( rvalidbraces, "")) ) { -- -- return ( new Function( "return " + data ) )(); -- -- } -- jQuery.error( "Invalid JSON: " + data ); -- }, -- -- // Cross-browser xml parsing -- parseXML: function( data ) { -- if ( typeof data !== "string" || !data ) { -- return null; -- } -- var xml, tmp; -- try { -- if ( window.DOMParser ) { // Standard -- tmp = new DOMParser(); -- xml = tmp.parseFromString( data , "text/xml" ); -- } else { // IE -- xml = new ActiveXObject( "Microsoft.XMLDOM" ); -- xml.async = "false"; -- xml.loadXML( data ); -- } -- } catch( e ) { -- xml = undefined; -- } -- if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { -- jQuery.error( "Invalid XML: " + data ); -- } -- return xml; -- }, -- -- noop: function() {}, -- -- // Evaluates a script in a global context -- // Workarounds based on findings by Jim Driscoll -- // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context -- globalEval: function( data ) { -- if ( data && rnotwhite.test( data ) ) { -- // We use execScript on Internet Explorer -- // We use an anonymous function so that context is window -- // rather than jQuery in Firefox -- ( window.execScript || function( data ) { -- window[ "eval" ].call( window, data ); -- } )( data ); -- } -- }, -- -- // Convert dashed to camelCase; used by the css and data modules -- // Microsoft forgot to hump their vendor prefix (#9572) -- camelCase: function( string ) { -- return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); -- }, -- -- nodeName: function( elem, name ) { -- return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); -- }, -- -- // args is for internal usage only -- each: function( object, callback, args ) { -- var name, i = 0, -- length = object.length, -- isObj = length === undefined || jQuery.isFunction( object ); -- -- if ( args ) { -- if ( isObj ) { -- for ( name in object ) { -- if ( callback.apply( object[ name ], args ) === false ) { -- break; -- } -- } -- } else { -- for ( ; i < length; ) { -- if ( callback.apply( object[ i++ ], args ) === false ) { -- break; -- } -- } -- } -- -- // A special, fast, case for the most common use of each -- } else { -- if ( isObj ) { -- for ( name in object ) { -- if ( callback.call( object[ name ], name, object[ name ] ) === false ) { -- break; -- } -- } -- } else { -- for ( ; i < length; ) { -- if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { -- break; -- } -- } -- } -- } -- -- return object; -- }, -- -- // Use native String.trim function wherever possible -- trim: trim ? -- function( text ) { -- return text == null ? -- "" : -- trim.call( text ); -- } : -- -- // Otherwise use our own trimming functionality -- function( text ) { -- return text == null ? -- "" : -- text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); -- }, -- -- // results is for internal usage only -- makeArray: function( array, results ) { -- var ret = results || []; -- -- if ( array != null ) { -- // The window, strings (and functions) also have 'length' -- // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 -- var type = jQuery.type( array ); -- -- if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { -- push.call( ret, array ); -- } else { -- jQuery.merge( ret, array ); -- } -- } -- -- return ret; -- }, -- -- inArray: function( elem, array, i ) { -- var len; -- -- if ( array ) { -- if ( indexOf ) { -- return indexOf.call( array, elem, i ); -- } -- -- len = array.length; -- i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; -- -- for ( ; i < len; i++ ) { -- // Skip accessing in sparse arrays -- if ( i in array && array[ i ] === elem ) { -- return i; -- } -- } -- } -- -- return -1; -- }, -- -- merge: function( first, second ) { -- var i = first.length, -- j = 0; -- -- if ( typeof second.length === "number" ) { -- for ( var l = second.length; j < l; j++ ) { -- first[ i++ ] = second[ j ]; -- } -- -- } else { -- while ( second[j] !== undefined ) { -- first[ i++ ] = second[ j++ ]; -- } -- } -- -- first.length = i; -- -- return first; -- }, -- -- grep: function( elems, callback, inv ) { -- var ret = [], retVal; -- inv = !!inv; -- -- // Go through the array, only saving the items -- // that pass the validator function -- for ( var i = 0, length = elems.length; i < length; i++ ) { -- retVal = !!callback( elems[ i ], i ); -- if ( inv !== retVal ) { -- ret.push( elems[ i ] ); -- } -- } -- -- return ret; -- }, -- -- // arg is for internal usage only -- map: function( elems, callback, arg ) { -- var value, key, ret = [], -- i = 0, -- length = elems.length, -- // jquery objects are treated as arrays -- isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; -- -- // Go through the array, translating each of the items to their -- if ( isArray ) { -- for ( ; i < length; i++ ) { -- value = callback( elems[ i ], i, arg ); -- -- if ( value != null ) { -- ret[ ret.length ] = value; -- } -- } -- -- // Go through every key on the object, -- } else { -- for ( key in elems ) { -- value = callback( elems[ key ], key, arg ); -- -- if ( value != null ) { -- ret[ ret.length ] = value; -- } -- } -- } -- -- // Flatten any nested arrays -- return ret.concat.apply( [], ret ); -- }, -- -- // A global GUID counter for objects -- guid: 1, -- -- // Bind a function to a context, optionally partially applying any -- // arguments. -- proxy: function( fn, context ) { -- if ( typeof context === "string" ) { -- var tmp = fn[ context ]; -- context = fn; -- fn = tmp; -- } -- -- // Quick check to determine if target is callable, in the spec -- // this throws a TypeError, but we will just return undefined. -- if ( !jQuery.isFunction( fn ) ) { -- return undefined; -- } -- -- // Simulated bind -- var args = slice.call( arguments, 2 ), -- proxy = function() { -- return fn.apply( context, args.concat( slice.call( arguments ) ) ); -- }; -- -- // Set the guid of unique handler to the same of original handler, so it can be removed -- proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; -- -- return proxy; -- }, -- -- // Mutifunctional method to get and set values to a collection -- // The value/s can optionally be executed if it's a function -- access: function( elems, fn, key, value, chainable, emptyGet, pass ) { -- var exec, -- bulk = key == null, -- i = 0, -- length = elems.length; -- -- // Sets many values -- if ( key && typeof key === "object" ) { -- for ( i in key ) { -- jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); -- } -- chainable = 1; -- -- // Sets one value -- } else if ( value !== undefined ) { -- // Optionally, function values get executed if exec is true -- exec = pass === undefined && jQuery.isFunction( value ); -- -- if ( bulk ) { -- // Bulk operations only iterate when executing function values -- if ( exec ) { -- exec = fn; -- fn = function( elem, key, value ) { -- return exec.call( jQuery( elem ), value ); -- }; -- -- // Otherwise they run against the entire set -- } else { -- fn.call( elems, value ); -- fn = null; -- } -- } -- -- if ( fn ) { -- for (; i < length; i++ ) { -- fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); -- } -- } -- -- chainable = 1; -- } -- -- return chainable ? -- elems : -- -- // Gets -- bulk ? -- fn.call( elems ) : -- length ? fn( elems[0], key ) : emptyGet; -- }, -- -- now: function() { -- return ( new Date() ).getTime(); -- }, -- -- // Use of jQuery.browser is frowned upon. -- // More details: http://docs.jquery.com/Utilities/jQuery.browser -- uaMatch: function( ua ) { -- ua = ua.toLowerCase(); -- -- var match = rwebkit.exec( ua ) || -- ropera.exec( ua ) || -- rmsie.exec( ua ) || -- ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || -- []; -- -- return { browser: match[1] || "", version: match[2] || "0" }; -- }, -- -- sub: function() { -- function jQuerySub( selector, context ) { -- return new jQuerySub.fn.init( selector, context ); -- } -- jQuery.extend( true, jQuerySub, this ); -- jQuerySub.superclass = this; -- jQuerySub.fn = jQuerySub.prototype = this(); -- jQuerySub.fn.constructor = jQuerySub; -- jQuerySub.sub = this.sub; -- jQuerySub.fn.init = function init( selector, context ) { -- if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { -- context = jQuerySub( context ); -- } -- -- return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); -- }; -- jQuerySub.fn.init.prototype = jQuerySub.fn; -- var rootjQuerySub = jQuerySub(document); -- return jQuerySub; -- }, -- -- browser: {} --}); -- --// Populate the class2type map --jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { -- class2type[ "[object " + name + "]" ] = name.toLowerCase(); --}); -- --browserMatch = jQuery.uaMatch( userAgent ); --if ( browserMatch.browser ) { -- jQuery.browser[ browserMatch.browser ] = true; -- jQuery.browser.version = browserMatch.version; --} -- --// Deprecated, use jQuery.browser.webkit instead --if ( jQuery.browser.webkit ) { -- jQuery.browser.safari = true; --} -- --// IE doesn't match non-breaking spaces with \s --if ( rnotwhite.test( "\xA0" ) ) { -- trimLeft = /^[\s\xA0]+/; -- trimRight = /[\s\xA0]+$/; --} -- --// All jQuery objects should point back to these --rootjQuery = jQuery(document); -- --// Cleanup functions for the document ready method --if ( document.addEventListener ) { -- DOMContentLoaded = function() { -- document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); -- jQuery.ready(); -- }; -- --} else if ( document.attachEvent ) { -- DOMContentLoaded = function() { -- // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). -- if ( document.readyState === "complete" ) { -- document.detachEvent( "onreadystatechange", DOMContentLoaded ); -- jQuery.ready(); -- } -- }; --} -- --// The DOM ready check for Internet Explorer --function doScrollCheck() { -- if ( jQuery.isReady ) { -- return; -- } -- -- try { -- // If IE is used, use the trick by Diego Perini -- // http://javascript.nwbox.com/IEContentLoaded/ -- document.documentElement.doScroll("left"); -- } catch(e) { -- setTimeout( doScrollCheck, 1 ); -- return; -- } -- -- // and execute any waiting functions -- jQuery.ready(); --} -- --return jQuery; -- --})(); -- -- --// String to Object flags format cache --var flagsCache = {}; -- --// Convert String-formatted flags into Object-formatted ones and store in cache --function createFlags( flags ) { -- var object = flagsCache[ flags ] = {}, -- i, length; -- flags = flags.split( /\s+/ ); -- for ( i = 0, length = flags.length; i < length; i++ ) { -- object[ flags[i] ] = true; -- } -- return object; --} -- --/* -- * Create a callback list using the following parameters: -- * -- * flags: an optional list of space-separated flags that will change how -- * the callback list behaves -- * -- * By default a callback list will act like an event callback list and can be -- * "fired" multiple times. -- * -- * Possible flags: -- * -- * once: will ensure the callback list can only be fired once (like a Deferred) -- * -- * memory: will keep track of previous values and will call any callback added -- * after the list has been fired right away with the latest "memorized" -- * values (like a Deferred) -- * -- * unique: will ensure a callback can only be added once (no duplicate in the list) -- * -- * stopOnFalse: interrupt callings when a callback returns false -- * -- */ --jQuery.Callbacks = function( flags ) { -- -- // Convert flags from String-formatted to Object-formatted -- // (we check in cache first) -- flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {}; -- -- var // Actual callback list -- list = [], -- // Stack of fire calls for repeatable lists -- stack = [], -- // Last fire value (for non-forgettable lists) -- memory, -- // Flag to know if list was already fired -- fired, -- // Flag to know if list is currently firing -- firing, -- // First callback to fire (used internally by add and fireWith) -- firingStart, -- // End of the loop when firing -- firingLength, -- // Index of currently firing callback (modified by remove if needed) -- firingIndex, -- // Add one or several callbacks to the list -- add = function( args ) { -- var i, -- length, -- elem, -- type, -- actual; -- for ( i = 0, length = args.length; i < length; i++ ) { -- elem = args[ i ]; -- type = jQuery.type( elem ); -- if ( type === "array" ) { -- // Inspect recursively -- add( elem ); -- } else if ( type === "function" ) { -- // Add if not in unique mode and callback is not in -- if ( !flags.unique || !self.has( elem ) ) { -- list.push( elem ); -- } -- } -- } -- }, -- // Fire callbacks -- fire = function( context, args ) { -- args = args || []; -- memory = !flags.memory || [ context, args ]; -- fired = true; -- firing = true; -- firingIndex = firingStart || 0; -- firingStart = 0; -- firingLength = list.length; -- for ( ; list && firingIndex < firingLength; firingIndex++ ) { -- if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) { -- memory = true; // Mark as halted -- break; -- } -- } -- firing = false; -- if ( list ) { -- if ( !flags.once ) { -- if ( stack && stack.length ) { -- memory = stack.shift(); -- self.fireWith( memory[ 0 ], memory[ 1 ] ); -- } -- } else if ( memory === true ) { -- self.disable(); -- } else { -- list = []; -- } -- } -- }, -- // Actual Callbacks object -- self = { -- // Add a callback or a collection of callbacks to the list -- add: function() { -- if ( list ) { -- var length = list.length; -- add( arguments ); -- // Do we need to add the callbacks to the -- // current firing batch? -- if ( firing ) { -- firingLength = list.length; -- // With memory, if we're not firing then -- // we should call right away, unless previous -- // firing was halted (stopOnFalse) -- } else if ( memory && memory !== true ) { -- firingStart = length; -- fire( memory[ 0 ], memory[ 1 ] ); -- } -- } -- return this; -- }, -- // Remove a callback from the list -- remove: function() { -- if ( list ) { -- var args = arguments, -- argIndex = 0, -- argLength = args.length; -- for ( ; argIndex < argLength ; argIndex++ ) { -- for ( var i = 0; i < list.length; i++ ) { -- if ( args[ argIndex ] === list[ i ] ) { -- // Handle firingIndex and firingLength -- if ( firing ) { -- if ( i <= firingLength ) { -- firingLength--; -- if ( i <= firingIndex ) { -- firingIndex--; -- } -- } -- } -- // Remove the element -- list.splice( i--, 1 ); -- // If we have some unicity property then -- // we only need to do this once -- if ( flags.unique ) { -- break; -- } -- } -- } -- } -- } -- return this; -- }, -- // Control if a given callback is in the list -- has: function( fn ) { -- if ( list ) { -- var i = 0, -- length = list.length; -- for ( ; i < length; i++ ) { -- if ( fn === list[ i ] ) { -- return true; -- } -- } -- } -- return false; -- }, -- // Remove all callbacks from the list -- empty: function() { -- list = []; -- return this; -- }, -- // Have the list do nothing anymore -- disable: function() { -- list = stack = memory = undefined; -- return this; -- }, -- // Is it disabled? -- disabled: function() { -- return !list; -- }, -- // Lock the list in its current state -- lock: function() { -- stack = undefined; -- if ( !memory || memory === true ) { -- self.disable(); -- } -- return this; -- }, -- // Is it locked? -- locked: function() { -- return !stack; -- }, -- // Call all callbacks with the given context and arguments -- fireWith: function( context, args ) { -- if ( stack ) { -- if ( firing ) { -- if ( !flags.once ) { -- stack.push( [ context, args ] ); -- } -- } else if ( !( flags.once && memory ) ) { -- fire( context, args ); -- } -- } -- return this; -- }, -- // Call all the callbacks with the given arguments -- fire: function() { -- self.fireWith( this, arguments ); -- return this; -- }, -- // To know if the callbacks have already been called at least once -- fired: function() { -- return !!fired; -- } -- }; -- -- return self; --}; -- -- -- -- --var // Static reference to slice -- sliceDeferred = [].slice; -- --jQuery.extend({ -- -- Deferred: function( func ) { -- var doneList = jQuery.Callbacks( "once memory" ), -- failList = jQuery.Callbacks( "once memory" ), -- progressList = jQuery.Callbacks( "memory" ), -- state = "pending", -- lists = { -- resolve: doneList, -- reject: failList, -- notify: progressList -- }, -- promise = { -- done: doneList.add, -- fail: failList.add, -- progress: progressList.add, -- -- state: function() { -- return state; -- }, -- -- // Deprecated -- isResolved: doneList.fired, -- isRejected: failList.fired, -- -- then: function( doneCallbacks, failCallbacks, progressCallbacks ) { -- deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks ); -- return this; -- }, -- always: function() { -- deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments ); -- return this; -- }, -- pipe: function( fnDone, fnFail, fnProgress ) { -- return jQuery.Deferred(function( newDefer ) { -- jQuery.each( { -- done: [ fnDone, "resolve" ], -- fail: [ fnFail, "reject" ], -- progress: [ fnProgress, "notify" ] -- }, function( handler, data ) { -- var fn = data[ 0 ], -- action = data[ 1 ], -- returned; -- if ( jQuery.isFunction( fn ) ) { -- deferred[ handler ](function() { -- returned = fn.apply( this, arguments ); -- if ( returned && jQuery.isFunction( returned.promise ) ) { -- returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify ); -- } else { -- newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); -- } -- }); -- } else { -- deferred[ handler ]( newDefer[ action ] ); -- } -- }); -- }).promise(); -- }, -- // Get a promise for this deferred -- // If obj is provided, the promise aspect is added to the object -- promise: function( obj ) { -- if ( obj == null ) { -- obj = promise; -- } else { -- for ( var key in promise ) { -- obj[ key ] = promise[ key ]; -- } -- } -- return obj; -- } -- }, -- deferred = promise.promise({}), -- key; -- -- for ( key in lists ) { -- deferred[ key ] = lists[ key ].fire; -- deferred[ key + "With" ] = lists[ key ].fireWith; -- } -- -- // Handle state -- deferred.done( function() { -- state = "resolved"; -- }, failList.disable, progressList.lock ).fail( function() { -- state = "rejected"; -- }, doneList.disable, progressList.lock ); -- -- // Call given func if any -- if ( func ) { -- func.call( deferred, deferred ); -- } -- -- // All done! -- return deferred; -- }, -- -- // Deferred helper -- when: function( firstParam ) { -- var args = sliceDeferred.call( arguments, 0 ), -- i = 0, -- length = args.length, -- pValues = new Array( length ), -- count = length, -- pCount = length, -- deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? -- firstParam : -- jQuery.Deferred(), -- promise = deferred.promise(); -- function resolveFunc( i ) { -- return function( value ) { -- args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; -- if ( !( --count ) ) { -- deferred.resolveWith( deferred, args ); -- } -- }; -- } -- function progressFunc( i ) { -- return function( value ) { -- pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; -- deferred.notifyWith( promise, pValues ); -- }; -- } -- if ( length > 1 ) { -- for ( ; i < length; i++ ) { -- if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) { -- args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) ); -- } else { -- --count; -- } -- } -- if ( !count ) { -- deferred.resolveWith( deferred, args ); -- } -- } else if ( deferred !== firstParam ) { -- deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); -- } -- return promise; -- } --}); -- -- -- -- --jQuery.support = (function() { -- -- var support, -- all, -- a, -- select, -- opt, -- input, -- fragment, -- tds, -- events, -- eventName, -- i, -- isSupported, -- div = document.createElement( "div" ), -- documentElement = document.documentElement; -- -- // Preliminary tests -- div.setAttribute("className", "t"); -- div.innerHTML = "
a"; -- -- all = div.getElementsByTagName( "*" ); -- a = div.getElementsByTagName( "a" )[ 0 ]; -- -- // Can't get basic test support -- if ( !all || !all.length || !a ) { -- return {}; -- } -- -- // First batch of supports tests -- select = document.createElement( "select" ); -- opt = select.appendChild( document.createElement("option") ); -- input = div.getElementsByTagName( "input" )[ 0 ]; -- -- support = { -- // IE strips leading whitespace when .innerHTML is used -- leadingWhitespace: ( div.firstChild.nodeType === 3 ), -- -- // Make sure that tbody elements aren't automatically inserted -- // IE will insert them into empty tables -- tbody: !div.getElementsByTagName("tbody").length, -- -- // Make sure that link elements get serialized correctly by innerHTML -- // This requires a wrapper element in IE -- htmlSerialize: !!div.getElementsByTagName("link").length, -- -- // Get the style information from getAttribute -- // (IE uses .cssText instead) -- style: /top/.test( a.getAttribute("style") ), -- -- // Make sure that URLs aren't manipulated -- // (IE normalizes it by default) -- hrefNormalized: ( a.getAttribute("href") === "/a" ), -- -- // Make sure that element opacity exists -- // (IE uses filter instead) -- // Use a regex to work around a WebKit issue. See #5145 -- opacity: /^0.55/.test( a.style.opacity ), -- -- // Verify style float existence -- // (IE uses styleFloat instead of cssFloat) -- cssFloat: !!a.style.cssFloat, -- -- // Make sure that if no value is specified for a checkbox -- // that it defaults to "on". -- // (WebKit defaults to "" instead) -- checkOn: ( input.value === "on" ), -- -- // Make sure that a selected-by-default option has a working selected property. -- // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) -- optSelected: opt.selected, -- -- // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) -- getSetAttribute: div.className !== "t", -- -- // Tests for enctype support on a form(#6743) -- enctype: !!document.createElement("form").enctype, -- -- // Makes sure cloning an html5 element does not cause problems -- // Where outerHTML is undefined, this still works -- html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", -- -- // Will be defined later -- submitBubbles: true, -- changeBubbles: true, -- focusinBubbles: false, -- deleteExpando: true, -- noCloneEvent: true, -- inlineBlockNeedsLayout: false, -- shrinkWrapBlocks: false, -- reliableMarginRight: true, -- pixelMargin: true -- }; -- -- // jQuery.boxModel DEPRECATED in 1.3, use jQuery.support.boxModel instead -- jQuery.boxModel = support.boxModel = (document.compatMode === "CSS1Compat"); -- -- // Make sure checked status is properly cloned -- input.checked = true; -- support.noCloneChecked = input.cloneNode( true ).checked; -- -- // Make sure that the options inside disabled selects aren't marked as disabled -- // (WebKit marks them as disabled) -- select.disabled = true; -- support.optDisabled = !opt.disabled; -- -- // Test to see if it's possible to delete an expando from an element -- // Fails in Internet Explorer -- try { -- delete div.test; -- } catch( e ) { -- support.deleteExpando = false; -- } -- -- if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { -- div.attachEvent( "onclick", function() { -- // Cloning a node shouldn't copy over any -- // bound event handlers (IE does this) -- support.noCloneEvent = false; -- }); -- div.cloneNode( true ).fireEvent( "onclick" ); -- } -- -- // Check if a radio maintains its value -- // after being appended to the DOM -- input = document.createElement("input"); -- input.value = "t"; -- input.setAttribute("type", "radio"); -- support.radioValue = input.value === "t"; -- -- input.setAttribute("checked", "checked"); -- -- // #11217 - WebKit loses check when the name is after the checked attribute -- input.setAttribute( "name", "t" ); -- -- div.appendChild( input ); -- fragment = document.createDocumentFragment(); -- fragment.appendChild( div.lastChild ); -- -- // WebKit doesn't clone checked state correctly in fragments -- support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; -- -- // Check if a disconnected checkbox will retain its checked -- // value of true after appended to the DOM (IE6/7) -- support.appendChecked = input.checked; -- -- fragment.removeChild( input ); -- fragment.appendChild( div ); -- -- // Technique from Juriy Zaytsev -- // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ -- // We only care about the case where non-standard event systems -- // are used, namely in IE. Short-circuiting here helps us to -- // avoid an eval call (in setAttribute) which can cause CSP -- // to go haywire. See: https://developer.mozilla.org/en/Security/CSP -- if ( div.attachEvent ) { -- for ( i in { -- submit: 1, -- change: 1, -- focusin: 1 -- }) { -- eventName = "on" + i; -- isSupported = ( eventName in div ); -- if ( !isSupported ) { -- div.setAttribute( eventName, "return;" ); -- isSupported = ( typeof div[ eventName ] === "function" ); -- } -- support[ i + "Bubbles" ] = isSupported; -- } -- } -- -- fragment.removeChild( div ); -- -- // Null elements to avoid leaks in IE -- fragment = select = opt = div = input = null; -- -- // Run tests that need a body at doc ready -- jQuery(function() { -- var container, outer, inner, table, td, offsetSupport, -- marginDiv, conMarginTop, style, html, positionTopLeftWidthHeight, -- paddingMarginBorderVisibility, paddingMarginBorder, -- body = document.getElementsByTagName("body")[0]; -- -- if ( !body ) { -- // Return for frameset docs that don't have a body -- return; -- } -- -- conMarginTop = 1; -- paddingMarginBorder = "padding:0;margin:0;border:"; -- positionTopLeftWidthHeight = "position:absolute;top:0;left:0;width:1px;height:1px;"; -- paddingMarginBorderVisibility = paddingMarginBorder + "0;visibility:hidden;"; -- style = "style='" + positionTopLeftWidthHeight + paddingMarginBorder + "5px solid #000;"; -- html = "
" + -- "" + -- "
"; -- -- container = document.createElement("div"); -- container.style.cssText = paddingMarginBorderVisibility + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px"; -- body.insertBefore( container, body.firstChild ); -- -- // Construct the test element -- div = document.createElement("div"); -- container.appendChild( div ); -- -- // Check if table cells still have offsetWidth/Height when they are set -- // to display:none and there are still other visible table cells in a -- // table row; if so, offsetWidth/Height are not reliable for use when -- // determining if an element has been hidden directly using -- // display:none (it is still safe to use offsets if a parent element is -- // hidden; don safety goggles and see bug #4512 for more information). -- // (only IE 8 fails this test) -- div.innerHTML = "
t
"; -- tds = div.getElementsByTagName( "td" ); -- isSupported = ( tds[ 0 ].offsetHeight === 0 ); -- -- tds[ 0 ].style.display = ""; -- tds[ 1 ].style.display = "none"; -- -- // Check if empty table cells still have offsetWidth/Height -- // (IE <= 8 fail this test) -- support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); -- -- // Check if div with explicit width and no margin-right incorrectly -- // gets computed margin-right based on width of container. For more -- // info see bug #3333 -- // Fails in WebKit before Feb 2011 nightlies -- // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right -- if ( window.getComputedStyle ) { -- div.innerHTML = ""; -- marginDiv = document.createElement( "div" ); -- marginDiv.style.width = "0"; -- marginDiv.style.marginRight = "0"; -- div.style.width = "2px"; -- div.appendChild( marginDiv ); -- support.reliableMarginRight = -- ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; -- } -- -- if ( typeof div.style.zoom !== "undefined" ) { -- // Check if natively block-level elements act like inline-block -- // elements when setting their display to 'inline' and giving -- // them layout -- // (IE < 8 does this) -- div.innerHTML = ""; -- div.style.width = div.style.padding = "1px"; -- div.style.border = 0; -- div.style.overflow = "hidden"; -- div.style.display = "inline"; -- div.style.zoom = 1; -- support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); -- -- // Check if elements with layout shrink-wrap their children -- // (IE 6 does this) -- div.style.display = "block"; -- div.style.overflow = "visible"; -- div.innerHTML = "
"; -- support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); -- } -- -- div.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility; -- div.innerHTML = html; -- -- outer = div.firstChild; -- inner = outer.firstChild; -- td = outer.nextSibling.firstChild.firstChild; -- -- offsetSupport = { -- doesNotAddBorder: ( inner.offsetTop !== 5 ), -- doesAddBorderForTableAndCells: ( td.offsetTop === 5 ) -- }; -- -- inner.style.position = "fixed"; -- inner.style.top = "20px"; -- -- // safari subtracts parent border width here which is 5px -- offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 ); -- inner.style.position = inner.style.top = ""; -- -- outer.style.overflow = "hidden"; -- outer.style.position = "relative"; -- -- offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 ); -- offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop ); -- -- if ( window.getComputedStyle ) { -- div.style.marginTop = "1%"; -- support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%"; -- } -- -- if ( typeof container.style.zoom !== "undefined" ) { -- container.style.zoom = 1; -- } -- -- body.removeChild( container ); -- marginDiv = div = container = null; -- -- jQuery.extend( support, offsetSupport ); -- }); -- -- return support; --})(); -- -- -- -- --var rbrace = /^(?:\{.*\}|\[.*\])$/, -- rmultiDash = /([A-Z])/g; -- --jQuery.extend({ -- cache: {}, -- -- // Please use with caution -- uuid: 0, -- -- // Unique for each copy of jQuery on the page -- // Non-digits removed to match rinlinejQuery -- expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), -- -- // The following elements throw uncatchable exceptions if you -- // attempt to add expando properties to them. -- noData: { -- "embed": true, -- // Ban all objects except for Flash (which handle expandos) -- "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", -- "applet": true -- }, -- -- hasData: function( elem ) { -- elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; -- return !!elem && !isEmptyDataObject( elem ); -- }, -- -- data: function( elem, name, data, pvt /* Internal Use Only */ ) { -- if ( !jQuery.acceptData( elem ) ) { -- return; -- } -- -- var privateCache, thisCache, ret, -- internalKey = jQuery.expando, -- getByName = typeof name === "string", -- -- // We have to handle DOM nodes and JS objects differently because IE6-7 -- // can't GC object references properly across the DOM-JS boundary -- isNode = elem.nodeType, -- -- // Only DOM nodes need the global jQuery cache; JS object data is -- // attached directly to the object so GC can occur automatically -- cache = isNode ? jQuery.cache : elem, -- -- // Only defining an ID for JS objects if its cache already exists allows -- // the code to shortcut on the same path as a DOM node with no cache -- id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey, -- isEvents = name === "events"; -- -- // Avoid doing any more work than we need to when trying to get data on an -- // object that has no data at all -- if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) { -- return; -- } -- -- if ( !id ) { -- // Only DOM nodes need a new unique ID for each element since their data -- // ends up in the global cache -- if ( isNode ) { -- elem[ internalKey ] = id = ++jQuery.uuid; -- } else { -- id = internalKey; -- } -- } -- -- if ( !cache[ id ] ) { -- cache[ id ] = {}; -- -- // Avoids exposing jQuery metadata on plain JS objects when the object -- // is serialized using JSON.stringify -- if ( !isNode ) { -- cache[ id ].toJSON = jQuery.noop; -- } -- } -- -- // An object can be passed to jQuery.data instead of a key/value pair; this gets -- // shallow copied over onto the existing cache -- if ( typeof name === "object" || typeof name === "function" ) { -- if ( pvt ) { -- cache[ id ] = jQuery.extend( cache[ id ], name ); -- } else { -- cache[ id ].data = jQuery.extend( cache[ id ].data, name ); -- } -- } -- -- privateCache = thisCache = cache[ id ]; -- -- // jQuery data() is stored in a separate object inside the object's internal data -- // cache in order to avoid key collisions between internal data and user-defined -- // data. -- if ( !pvt ) { -- if ( !thisCache.data ) { -- thisCache.data = {}; -- } -- -- thisCache = thisCache.data; -- } -- -- if ( data !== undefined ) { -- thisCache[ jQuery.camelCase( name ) ] = data; -- } -- -- // Users should not attempt to inspect the internal events object using jQuery.data, -- // it is undocumented and subject to change. But does anyone listen? No. -- if ( isEvents && !thisCache[ name ] ) { -- return privateCache.events; -- } -- -- // Check for both converted-to-camel and non-converted data property names -- // If a data property was specified -- if ( getByName ) { -- -- // First Try to find as-is property data -- ret = thisCache[ name ]; -- -- // Test for null|undefined property data -- if ( ret == null ) { -- -- // Try to find the camelCased property -- ret = thisCache[ jQuery.camelCase( name ) ]; -- } -- } else { -- ret = thisCache; -- } -- -- return ret; -- }, -- -- removeData: function( elem, name, pvt /* Internal Use Only */ ) { -- if ( !jQuery.acceptData( elem ) ) { -- return; -- } -- -- var thisCache, i, l, -- -- // Reference to internal data cache key -- internalKey = jQuery.expando, -- -- isNode = elem.nodeType, -- -- // See jQuery.data for more information -- cache = isNode ? jQuery.cache : elem, -- -- // See jQuery.data for more information -- id = isNode ? elem[ internalKey ] : internalKey; -- -- // If there is already no cache entry for this object, there is no -- // purpose in continuing -- if ( !cache[ id ] ) { -- return; -- } -- -- if ( name ) { -- -- thisCache = pvt ? cache[ id ] : cache[ id ].data; -- -- if ( thisCache ) { -- -- // Support array or space separated string names for data keys -- if ( !jQuery.isArray( name ) ) { -- -- // try the string as a key before any manipulation -- if ( name in thisCache ) { -- name = [ name ]; -- } else { -- -- // split the camel cased version by spaces unless a key with the spaces exists -- name = jQuery.camelCase( name ); -- if ( name in thisCache ) { -- name = [ name ]; -- } else { -- name = name.split( " " ); -- } -- } -- } -- -- for ( i = 0, l = name.length; i < l; i++ ) { -- delete thisCache[ name[i] ]; -- } -- -- // If there is no data left in the cache, we want to continue -- // and let the cache object itself get destroyed -- if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { -- return; -- } -- } -- } -- -- // See jQuery.data for more information -- if ( !pvt ) { -- delete cache[ id ].data; -- -- // Don't destroy the parent cache unless the internal data object -- // had been the only thing left in it -- if ( !isEmptyDataObject(cache[ id ]) ) { -- return; -- } -- } -- -- // Browsers that fail expando deletion also refuse to delete expandos on -- // the window, but it will allow it on all other JS objects; other browsers -- // don't care -- // Ensure that `cache` is not a window object #10080 -- if ( jQuery.support.deleteExpando || !cache.setInterval ) { -- delete cache[ id ]; -- } else { -- cache[ id ] = null; -- } -- -- // We destroyed the cache and need to eliminate the expando on the node to avoid -- // false lookups in the cache for entries that no longer exist -- if ( isNode ) { -- // IE does not allow us to delete expando properties from nodes, -- // nor does it have a removeAttribute function on Document nodes; -- // we must handle all of these cases -- if ( jQuery.support.deleteExpando ) { -- delete elem[ internalKey ]; -- } else if ( elem.removeAttribute ) { -- elem.removeAttribute( internalKey ); -- } else { -- elem[ internalKey ] = null; -- } -- } -- }, -- -- // For internal use only. -- _data: function( elem, name, data ) { -- return jQuery.data( elem, name, data, true ); -- }, -- -- // A method for determining if a DOM node can handle the data expando -- acceptData: function( elem ) { -- if ( elem.nodeName ) { -- var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; -- -- if ( match ) { -- return !(match === true || elem.getAttribute("classid") !== match); -- } -- } -- -- return true; -- } --}); -- --jQuery.fn.extend({ -- data: function( key, value ) { -- var parts, part, attr, name, l, -- elem = this[0], -- i = 0, -- data = null; -- -- // Gets all values -- if ( key === undefined ) { -- if ( this.length ) { -- data = jQuery.data( elem ); -- -- if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { -- attr = elem.attributes; -- for ( l = attr.length; i < l; i++ ) { -- name = attr[i].name; -- -- if ( name.indexOf( "data-" ) === 0 ) { -- name = jQuery.camelCase( name.substring(5) ); -- -- dataAttr( elem, name, data[ name ] ); -- } -- } -- jQuery._data( elem, "parsedAttrs", true ); -- } -- } -- -- return data; -- } -- -- // Sets multiple values -- if ( typeof key === "object" ) { -- return this.each(function() { -- jQuery.data( this, key ); -- }); -- } -- -- parts = key.split( ".", 2 ); -- parts[1] = parts[1] ? "." + parts[1] : ""; -- part = parts[1] + "!"; -- -- return jQuery.access( this, function( value ) { -- -- if ( value === undefined ) { -- data = this.triggerHandler( "getData" + part, [ parts[0] ] ); -- -- // Try to fetch any internally stored data first -- if ( data === undefined && elem ) { -- data = jQuery.data( elem, key ); -- data = dataAttr( elem, key, data ); -- } -- -- return data === undefined && parts[1] ? -- this.data( parts[0] ) : -- data; -- } -- -- parts[1] = value; -- this.each(function() { -- var self = jQuery( this ); -- -- self.triggerHandler( "setData" + part, parts ); -- jQuery.data( this, key, value ); -- self.triggerHandler( "changeData" + part, parts ); -- }); -- }, null, value, arguments.length > 1, null, false ); -- }, -- -- removeData: function( key ) { -- return this.each(function() { -- jQuery.removeData( this, key ); -- }); -- } --}); -- --function dataAttr( elem, key, data ) { -- // If nothing was found internally, try to fetch any -- // data from the HTML5 data-* attribute -- if ( data === undefined && elem.nodeType === 1 ) { -- -- var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); -- -- data = elem.getAttribute( name ); -- -- if ( typeof data === "string" ) { -- try { -- data = data === "true" ? true : -- data === "false" ? false : -- data === "null" ? null : -- jQuery.isNumeric( data ) ? +data : -- rbrace.test( data ) ? jQuery.parseJSON( data ) : -- data; -- } catch( e ) {} -- -- // Make sure we set the data so it isn't changed later -- jQuery.data( elem, key, data ); -- -- } else { -- data = undefined; -- } -- } -- -- return data; --} -- --// checks a cache object for emptiness --function isEmptyDataObject( obj ) { -- for ( var name in obj ) { -- -- // if the public data object is empty, the private is still empty -- if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { -- continue; -- } -- if ( name !== "toJSON" ) { -- return false; -- } -- } -- -- return true; --} -- -- -- -- --function handleQueueMarkDefer( elem, type, src ) { -- var deferDataKey = type + "defer", -- queueDataKey = type + "queue", -- markDataKey = type + "mark", -- defer = jQuery._data( elem, deferDataKey ); -- if ( defer && -- ( src === "queue" || !jQuery._data(elem, queueDataKey) ) && -- ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) { -- // Give room for hard-coded callbacks to fire first -- // and eventually mark/queue something else on the element -- setTimeout( function() { -- if ( !jQuery._data( elem, queueDataKey ) && -- !jQuery._data( elem, markDataKey ) ) { -- jQuery.removeData( elem, deferDataKey, true ); -- defer.fire(); -- } -- }, 0 ); -- } --} -- --jQuery.extend({ -- -- _mark: function( elem, type ) { -- if ( elem ) { -- type = ( type || "fx" ) + "mark"; -- jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 ); -- } -- }, -- -- _unmark: function( force, elem, type ) { -- if ( force !== true ) { -- type = elem; -- elem = force; -- force = false; -- } -- if ( elem ) { -- type = type || "fx"; -- var key = type + "mark", -- count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 ); -- if ( count ) { -- jQuery._data( elem, key, count ); -- } else { -- jQuery.removeData( elem, key, true ); -- handleQueueMarkDefer( elem, type, "mark" ); -- } -- } -- }, -- -- queue: function( elem, type, data ) { -- var q; -- if ( elem ) { -- type = ( type || "fx" ) + "queue"; -- q = jQuery._data( elem, type ); -- -- // Speed up dequeue by getting out quickly if this is just a lookup -- if ( data ) { -- if ( !q || jQuery.isArray(data) ) { -- q = jQuery._data( elem, type, jQuery.makeArray(data) ); -- } else { -- q.push( data ); -- } -- } -- return q || []; -- } -- }, -- -- dequeue: function( elem, type ) { -- type = type || "fx"; -- -- var queue = jQuery.queue( elem, type ), -- fn = queue.shift(), -- hooks = {}; -- -- // If the fx queue is dequeued, always remove the progress sentinel -- if ( fn === "inprogress" ) { -- fn = queue.shift(); -- } -- -- if ( fn ) { -- // Add a progress sentinel to prevent the fx queue from being -- // automatically dequeued -- if ( type === "fx" ) { -- queue.unshift( "inprogress" ); -- } -- -- jQuery._data( elem, type + ".run", hooks ); -- fn.call( elem, function() { -- jQuery.dequeue( elem, type ); -- }, hooks ); -- } -- -- if ( !queue.length ) { -- jQuery.removeData( elem, type + "queue " + type + ".run", true ); -- handleQueueMarkDefer( elem, type, "queue" ); -- } -- } --}); -- --jQuery.fn.extend({ -- queue: function( type, data ) { -- var setter = 2; -- -- if ( typeof type !== "string" ) { -- data = type; -- type = "fx"; -- setter--; -- } -- -- if ( arguments.length < setter ) { -- return jQuery.queue( this[0], type ); -- } -- -- return data === undefined ? -- this : -- this.each(function() { -- var queue = jQuery.queue( this, type, data ); -- -- if ( type === "fx" && queue[0] !== "inprogress" ) { -- jQuery.dequeue( this, type ); -- } -- }); -- }, -- dequeue: function( type ) { -- return this.each(function() { -- jQuery.dequeue( this, type ); -- }); -- }, -- // Based off of the plugin by Clint Helfers, with permission. -- // http://blindsignals.com/index.php/2009/07/jquery-delay/ -- delay: function( time, type ) { -- time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; -- type = type || "fx"; -- -- return this.queue( type, function( next, hooks ) { -- var timeout = setTimeout( next, time ); -- hooks.stop = function() { -- clearTimeout( timeout ); -- }; -- }); -- }, -- clearQueue: function( type ) { -- return this.queue( type || "fx", [] ); -- }, -- // Get a promise resolved when queues of a certain type -- // are emptied (fx is the type by default) -- promise: function( type, object ) { -- if ( typeof type !== "string" ) { -- object = type; -- type = undefined; -- } -- type = type || "fx"; -- var defer = jQuery.Deferred(), -- elements = this, -- i = elements.length, -- count = 1, -- deferDataKey = type + "defer", -- queueDataKey = type + "queue", -- markDataKey = type + "mark", -- tmp; -- function resolve() { -- if ( !( --count ) ) { -- defer.resolveWith( elements, [ elements ] ); -- } -- } -- while( i-- ) { -- if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || -- ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || -- jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && -- jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) { -- count++; -- tmp.add( resolve ); -- } -- } -- resolve(); -- return defer.promise( object ); -- } --}); -- -- -- -- --var rclass = /[\n\t\r]/g, -- rspace = /\s+/, -- rreturn = /\r/g, -- rtype = /^(?:button|input)$/i, -- rfocusable = /^(?:button|input|object|select|textarea)$/i, -- rclickable = /^a(?:rea)?$/i, -- rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, -- getSetAttribute = jQuery.support.getSetAttribute, -- nodeHook, boolHook, fixSpecified; -- --jQuery.fn.extend({ -- attr: function( name, value ) { -- return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); -- }, -- -- removeAttr: function( name ) { -- return this.each(function() { -- jQuery.removeAttr( this, name ); -- }); -- }, -- -- prop: function( name, value ) { -- return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); -- }, -- -- removeProp: function( name ) { -- name = jQuery.propFix[ name ] || name; -- return this.each(function() { -- // try/catch handles cases where IE balks (such as removing a property on window) -- try { -- this[ name ] = undefined; -- delete this[ name ]; -- } catch( e ) {} -- }); -- }, -- -- addClass: function( value ) { -- var classNames, i, l, elem, -- setClass, c, cl; -- -- if ( jQuery.isFunction( value ) ) { -- return this.each(function( j ) { -- jQuery( this ).addClass( value.call(this, j, this.className) ); -- }); -- } -- -- if ( value && typeof value === "string" ) { -- classNames = value.split( rspace ); -- -- for ( i = 0, l = this.length; i < l; i++ ) { -- elem = this[ i ]; -- -- if ( elem.nodeType === 1 ) { -- if ( !elem.className && classNames.length === 1 ) { -- elem.className = value; -- -- } else { -- setClass = " " + elem.className + " "; -- -- for ( c = 0, cl = classNames.length; c < cl; c++ ) { -- if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { -- setClass += classNames[ c ] + " "; -- } -- } -- elem.className = jQuery.trim( setClass ); -- } -- } -- } -- } -- -- return this; -- }, -- -- removeClass: function( value ) { -- var classNames, i, l, elem, className, c, cl; -- -- if ( jQuery.isFunction( value ) ) { -- return this.each(function( j ) { -- jQuery( this ).removeClass( value.call(this, j, this.className) ); -- }); -- } -- -- if ( (value && typeof value === "string") || value === undefined ) { -- classNames = ( value || "" ).split( rspace ); -- -- for ( i = 0, l = this.length; i < l; i++ ) { -- elem = this[ i ]; -- -- if ( elem.nodeType === 1 && elem.className ) { -- if ( value ) { -- className = (" " + elem.className + " ").replace( rclass, " " ); -- for ( c = 0, cl = classNames.length; c < cl; c++ ) { -- className = className.replace(" " + classNames[ c ] + " ", " "); -- } -- elem.className = jQuery.trim( className ); -- -- } else { -- elem.className = ""; -- } -- } -- } -- } -- -- return this; -- }, -- -- toggleClass: function( value, stateVal ) { -- var type = typeof value, -- isBool = typeof stateVal === "boolean"; -- -- if ( jQuery.isFunction( value ) ) { -- return this.each(function( i ) { -- jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); -- }); -- } -- -- return this.each(function() { -- if ( type === "string" ) { -- // toggle individual class names -- var className, -- i = 0, -- self = jQuery( this ), -- state = stateVal, -- classNames = value.split( rspace ); -- -- while ( (className = classNames[ i++ ]) ) { -- // check each className given, space seperated list -- state = isBool ? state : !self.hasClass( className ); -- self[ state ? "addClass" : "removeClass" ]( className ); -- } -- -- } else if ( type === "undefined" || type === "boolean" ) { -- if ( this.className ) { -- // store className if set -- jQuery._data( this, "__className__", this.className ); -- } -- -- // toggle whole className -- this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; -- } -- }); -- }, -- -- hasClass: function( selector ) { -- var className = " " + selector + " ", -- i = 0, -- l = this.length; -- for ( ; i < l; i++ ) { -- if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { -- return true; -- } -- } -- -- return false; -- }, -- -- val: function( value ) { -- var hooks, ret, isFunction, -- elem = this[0]; -- -- if ( !arguments.length ) { -- if ( elem ) { -- hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; -- -- if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { -- return ret; -- } -- -- ret = elem.value; -- -- return typeof ret === "string" ? -- // handle most common string cases -- ret.replace(rreturn, "") : -- // handle cases where value is null/undef or number -- ret == null ? "" : ret; -- } -- -- return; -- } -- -- isFunction = jQuery.isFunction( value ); -- -- return this.each(function( i ) { -- var self = jQuery(this), val; -- -- if ( this.nodeType !== 1 ) { -- return; -- } -- -- if ( isFunction ) { -- val = value.call( this, i, self.val() ); -- } else { -- val = value; -- } -- -- // Treat null/undefined as ""; convert numbers to string -- if ( val == null ) { -- val = ""; -- } else if ( typeof val === "number" ) { -- val += ""; -- } else if ( jQuery.isArray( val ) ) { -- val = jQuery.map(val, function ( value ) { -- return value == null ? "" : value + ""; -- }); -- } -- -- hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; -- -- // If set returns undefined, fall back to normal setting -- if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { -- this.value = val; -- } -- }); -- } --}); -- --jQuery.extend({ -- valHooks: { -- option: { -- get: function( elem ) { -- // attributes.value is undefined in Blackberry 4.7 but -- // uses .value. See #6932 -- var val = elem.attributes.value; -- return !val || val.specified ? elem.value : elem.text; -- } -- }, -- select: { -- get: function( elem ) { -- var value, i, max, option, -- index = elem.selectedIndex, -- values = [], -- options = elem.options, -- one = elem.type === "select-one"; -- -- // Nothing was selected -- if ( index < 0 ) { -- return null; -- } -- -- // Loop through all the selected options -- i = one ? index : 0; -- max = one ? index + 1 : options.length; -- for ( ; i < max; i++ ) { -- option = options[ i ]; -- -- // Don't return options that are disabled or in a disabled optgroup -- if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && -- (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { -- -- // Get the specific value for the option -- value = jQuery( option ).val(); -- -- // We don't need an array for one selects -- if ( one ) { -- return value; -- } -- -- // Multi-Selects return an array -- values.push( value ); -- } -- } -- -- // Fixes Bug #2551 -- select.val() broken in IE after form.reset() -- if ( one && !values.length && options.length ) { -- return jQuery( options[ index ] ).val(); -- } -- -- return values; -- }, -- -- set: function( elem, value ) { -- var values = jQuery.makeArray( value ); -- -- jQuery(elem).find("option").each(function() { -- this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; -- }); -- -- if ( !values.length ) { -- elem.selectedIndex = -1; -- } -- return values; -- } -- } -- }, -- -- attrFn: { -- val: true, -- css: true, -- html: true, -- text: true, -- data: true, -- width: true, -- height: true, -- offset: true -- }, -- -- attr: function( elem, name, value, pass ) { -- var ret, hooks, notxml, -- nType = elem.nodeType; -- -- // don't get/set attributes on text, comment and attribute nodes -- if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { -- return; -- } -- -- if ( pass && name in jQuery.attrFn ) { -- return jQuery( elem )[ name ]( value ); -- } -- -- // Fallback to prop when attributes are not supported -- if ( typeof elem.getAttribute === "undefined" ) { -- return jQuery.prop( elem, name, value ); -- } -- -- notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); -- -- // All attributes are lowercase -- // Grab necessary hook if one is defined -- if ( notxml ) { -- name = name.toLowerCase(); -- hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); -- } -- -- if ( value !== undefined ) { -- -- if ( value === null ) { -- jQuery.removeAttr( elem, name ); -- return; -- -- } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { -- return ret; -- -- } else { -- elem.setAttribute( name, "" + value ); -- return value; -- } -- -- } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { -- return ret; -- -- } else { -- -- ret = elem.getAttribute( name ); -- -- // Non-existent attributes return null, we normalize to undefined -- return ret === null ? -- undefined : -- ret; -- } -- }, -- -- removeAttr: function( elem, value ) { -- var propName, attrNames, name, l, isBool, -- i = 0; -- -- if ( value && elem.nodeType === 1 ) { -- attrNames = value.toLowerCase().split( rspace ); -- l = attrNames.length; -- -- for ( ; i < l; i++ ) { -- name = attrNames[ i ]; -- -- if ( name ) { -- propName = jQuery.propFix[ name ] || name; -- isBool = rboolean.test( name ); -- -- // See #9699 for explanation of this approach (setting first, then removal) -- // Do not do this for boolean attributes (see #10870) -- if ( !isBool ) { -- jQuery.attr( elem, name, "" ); -- } -- elem.removeAttribute( getSetAttribute ? name : propName ); -- -- // Set corresponding property to false for boolean attributes -- if ( isBool && propName in elem ) { -- elem[ propName ] = false; -- } -- } -- } -- } -- }, -- -- attrHooks: { -- type: { -- set: function( elem, value ) { -- // We can't allow the type property to be changed (since it causes problems in IE) -- if ( rtype.test( elem.nodeName ) && elem.parentNode ) { -- jQuery.error( "type property can't be changed" ); -- } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { -- // Setting the type on a radio button after the value resets the value in IE6-9 -- // Reset value to it's default in case type is set after value -- // This is for element creation -- var val = elem.value; -- elem.setAttribute( "type", value ); -- if ( val ) { -- elem.value = val; -- } -- return value; -- } -- } -- }, -- // Use the value property for back compat -- // Use the nodeHook for button elements in IE6/7 (#1954) -- value: { -- get: function( elem, name ) { -- if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { -- return nodeHook.get( elem, name ); -- } -- return name in elem ? -- elem.value : -- null; -- }, -- set: function( elem, value, name ) { -- if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { -- return nodeHook.set( elem, value, name ); -- } -- // Does not return so that setAttribute is also used -- elem.value = value; -- } -- } -- }, -- -- propFix: { -- tabindex: "tabIndex", -- readonly: "readOnly", -- "for": "htmlFor", -- "class": "className", -- maxlength: "maxLength", -- cellspacing: "cellSpacing", -- cellpadding: "cellPadding", -- rowspan: "rowSpan", -- colspan: "colSpan", -- usemap: "useMap", -- frameborder: "frameBorder", -- contenteditable: "contentEditable" -- }, -- -- prop: function( elem, name, value ) { -- var ret, hooks, notxml, -- nType = elem.nodeType; -- -- // don't get/set properties on text, comment and attribute nodes -- if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { -- return; -- } -- -- notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); -- -- if ( notxml ) { -- // Fix name and attach hooks -- name = jQuery.propFix[ name ] || name; -- hooks = jQuery.propHooks[ name ]; -- } -- -- if ( value !== undefined ) { -- if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { -- return ret; -- -- } else { -- return ( elem[ name ] = value ); -- } -- -- } else { -- if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { -- return ret; -- -- } else { -- return elem[ name ]; -- } -- } -- }, -- -- propHooks: { -- tabIndex: { -- get: function( elem ) { -- // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set -- // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ -- var attributeNode = elem.getAttributeNode("tabindex"); -- -- return attributeNode && attributeNode.specified ? -- parseInt( attributeNode.value, 10 ) : -- rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? -- 0 : -- undefined; -- } -- } -- } --}); -- --// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional) --jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex; -- --// Hook for boolean attributes --boolHook = { -- get: function( elem, name ) { -- // Align boolean attributes with corresponding properties -- // Fall back to attribute presence where some booleans are not supported -- var attrNode, -- property = jQuery.prop( elem, name ); -- return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? -- name.toLowerCase() : -- undefined; -- }, -- set: function( elem, value, name ) { -- var propName; -- if ( value === false ) { -- // Remove boolean attributes when set to false -- jQuery.removeAttr( elem, name ); -- } else { -- // value is true since we know at this point it's type boolean and not false -- // Set boolean attributes to the same name and set the DOM property -- propName = jQuery.propFix[ name ] || name; -- if ( propName in elem ) { -- // Only set the IDL specifically if it already exists on the element -- elem[ propName ] = true; -- } -- -- elem.setAttribute( name, name.toLowerCase() ); -- } -- return name; -- } --}; -- --// IE6/7 do not support getting/setting some attributes with get/setAttribute --if ( !getSetAttribute ) { -- -- fixSpecified = { -- name: true, -- id: true, -- coords: true -- }; -- -- // Use this for any attribute in IE6/7 -- // This fixes almost every IE6/7 issue -- nodeHook = jQuery.valHooks.button = { -- get: function( elem, name ) { -- var ret; -- ret = elem.getAttributeNode( name ); -- return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ? -- ret.nodeValue : -- undefined; -- }, -- set: function( elem, value, name ) { -- // Set the existing or create a new attribute node -- var ret = elem.getAttributeNode( name ); -- if ( !ret ) { -- ret = document.createAttribute( name ); -- elem.setAttributeNode( ret ); -- } -- return ( ret.nodeValue = value + "" ); -- } -- }; -- -- // Apply the nodeHook to tabindex -- jQuery.attrHooks.tabindex.set = nodeHook.set; -- -- // Set width and height to auto instead of 0 on empty string( Bug #8150 ) -- // This is for removals -- jQuery.each([ "width", "height" ], function( i, name ) { -- jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { -- set: function( elem, value ) { -- if ( value === "" ) { -- elem.setAttribute( name, "auto" ); -- return value; -- } -- } -- }); -- }); -- -- // Set contenteditable to false on removals(#10429) -- // Setting to empty string throws an error as an invalid value -- jQuery.attrHooks.contenteditable = { -- get: nodeHook.get, -- set: function( elem, value, name ) { -- if ( value === "" ) { -- value = "false"; -- } -- nodeHook.set( elem, value, name ); -- } -- }; --} -- -- --// Some attributes require a special call on IE --if ( !jQuery.support.hrefNormalized ) { -- jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { -- jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { -- get: function( elem ) { -- var ret = elem.getAttribute( name, 2 ); -- return ret === null ? undefined : ret; -- } -- }); -- }); --} -- --if ( !jQuery.support.style ) { -- jQuery.attrHooks.style = { -- get: function( elem ) { -- // Return undefined in the case of empty string -- // Normalize to lowercase since IE uppercases css property names -- return elem.style.cssText.toLowerCase() || undefined; -- }, -- set: function( elem, value ) { -- return ( elem.style.cssText = "" + value ); -- } -- }; --} -- --// Safari mis-reports the default selected property of an option --// Accessing the parent's selectedIndex property fixes it --if ( !jQuery.support.optSelected ) { -- jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { -- get: function( elem ) { -- var parent = elem.parentNode; -- -- if ( parent ) { -- parent.selectedIndex; -- -- // Make sure that it also works with optgroups, see #5701 -- if ( parent.parentNode ) { -- parent.parentNode.selectedIndex; -- } -- } -- return null; -- } -- }); --} -- --// IE6/7 call enctype encoding --if ( !jQuery.support.enctype ) { -- jQuery.propFix.enctype = "encoding"; --} -- --// Radios and checkboxes getter/setter --if ( !jQuery.support.checkOn ) { -- jQuery.each([ "radio", "checkbox" ], function() { -- jQuery.valHooks[ this ] = { -- get: function( elem ) { -- // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified -- return elem.getAttribute("value") === null ? "on" : elem.value; -- } -- }; -- }); --} --jQuery.each([ "radio", "checkbox" ], function() { -- jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { -- set: function( elem, value ) { -- if ( jQuery.isArray( value ) ) { -- return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); -- } -- } -- }); --}); -- -- -- -- --var rformElems = /^(?:textarea|input|select)$/i, -- rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/, -- rhoverHack = /(?:^|\s)hover(\.\S+)?\b/, -- rkeyEvent = /^key/, -- rmouseEvent = /^(?:mouse|contextmenu)|click/, -- rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, -- rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/, -- quickParse = function( selector ) { -- var quick = rquickIs.exec( selector ); -- if ( quick ) { -- // 0 1 2 3 -- // [ _, tag, id, class ] -- quick[1] = ( quick[1] || "" ).toLowerCase(); -- quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" ); -- } -- return quick; -- }, -- quickIs = function( elem, m ) { -- var attrs = elem.attributes || {}; -- return ( -- (!m[1] || elem.nodeName.toLowerCase() === m[1]) && -- (!m[2] || (attrs.id || {}).value === m[2]) && -- (!m[3] || m[3].test( (attrs[ "class" ] || {}).value )) -- ); -- }, -- hoverHack = function( events ) { -- return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); -- }; -- --/* -- * Helper functions for managing events -- not part of the public interface. -- * Props to Dean Edwards' addEvent library for many of the ideas. -- */ --jQuery.event = { -- -- add: function( elem, types, handler, data, selector ) { -- -- var elemData, eventHandle, events, -- t, tns, type, namespaces, handleObj, -- handleObjIn, quick, handlers, special; -- -- // Don't attach events to noData or text/comment nodes (allow plain objects tho) -- if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { -- return; -- } -- -- // Caller can pass in an object of custom data in lieu of the handler -- if ( handler.handler ) { -- handleObjIn = handler; -- handler = handleObjIn.handler; -- selector = handleObjIn.selector; -- } -- -- // Make sure that the handler has a unique ID, used to find/remove it later -- if ( !handler.guid ) { -- handler.guid = jQuery.guid++; -- } -- -- // Init the element's event structure and main handler, if this is the first -- events = elemData.events; -- if ( !events ) { -- elemData.events = events = {}; -- } -- eventHandle = elemData.handle; -- if ( !eventHandle ) { -- elemData.handle = eventHandle = function( e ) { -- // Discard the second event of a jQuery.event.trigger() and -- // when an event is called after a page has unloaded -- return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? -- jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : -- undefined; -- }; -- // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events -- eventHandle.elem = elem; -- } -- -- // Handle multiple events separated by a space -- // jQuery(...).bind("mouseover mouseout", fn); -- types = jQuery.trim( hoverHack(types) ).split( " " ); -- for ( t = 0; t < types.length; t++ ) { -- -- tns = rtypenamespace.exec( types[t] ) || []; -- type = tns[1]; -- namespaces = ( tns[2] || "" ).split( "." ).sort(); -- -- // If event changes its type, use the special event handlers for the changed type -- special = jQuery.event.special[ type ] || {}; -- -- // If selector defined, determine special event api type, otherwise given type -- type = ( selector ? special.delegateType : special.bindType ) || type; -- -- // Update special based on newly reset type -- special = jQuery.event.special[ type ] || {}; -- -- // handleObj is passed to all event handlers -- handleObj = jQuery.extend({ -- type: type, -- origType: tns[1], -- data: data, -- handler: handler, -- guid: handler.guid, -- selector: selector, -- quick: selector && quickParse( selector ), -- namespace: namespaces.join(".") -- }, handleObjIn ); -- -- // Init the event handler queue if we're the first -- handlers = events[ type ]; -- if ( !handlers ) { -- handlers = events[ type ] = []; -- handlers.delegateCount = 0; -- -- // Only use addEventListener/attachEvent if the special events handler returns false -- if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { -- // Bind the global event handler to the element -- if ( elem.addEventListener ) { -- elem.addEventListener( type, eventHandle, false ); -- -- } else if ( elem.attachEvent ) { -- elem.attachEvent( "on" + type, eventHandle ); -- } -- } -- } -- -- if ( special.add ) { -- special.add.call( elem, handleObj ); -- -- if ( !handleObj.handler.guid ) { -- handleObj.handler.guid = handler.guid; -- } -- } -- -- // Add to the element's handler list, delegates in front -- if ( selector ) { -- handlers.splice( handlers.delegateCount++, 0, handleObj ); -- } else { -- handlers.push( handleObj ); -- } -- -- // Keep track of which events have ever been used, for event optimization -- jQuery.event.global[ type ] = true; -- } -- -- // Nullify elem to prevent memory leaks in IE -- elem = null; -- }, -- -- global: {}, -- -- // Detach an event or set of events from an element -- remove: function( elem, types, handler, selector, mappedTypes ) { -- -- var elemData = jQuery.hasData( elem ) && jQuery._data( elem ), -- t, tns, type, origType, namespaces, origCount, -- j, events, special, handle, eventType, handleObj; -- -- if ( !elemData || !(events = elemData.events) ) { -- return; -- } -- -- // Once for each type.namespace in types; type may be omitted -- types = jQuery.trim( hoverHack( types || "" ) ).split(" "); -- for ( t = 0; t < types.length; t++ ) { -- tns = rtypenamespace.exec( types[t] ) || []; -- type = origType = tns[1]; -- namespaces = tns[2]; -- -- // Unbind all events (on this namespace, if provided) for the element -- if ( !type ) { -- for ( type in events ) { -- jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); -- } -- continue; -- } -- -- special = jQuery.event.special[ type ] || {}; -- type = ( selector? special.delegateType : special.bindType ) || type; -- eventType = events[ type ] || []; -- origCount = eventType.length; -- namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null; -- -- // Remove matching events -- for ( j = 0; j < eventType.length; j++ ) { -- handleObj = eventType[ j ]; -- -- if ( ( mappedTypes || origType === handleObj.origType ) && -- ( !handler || handler.guid === handleObj.guid ) && -- ( !namespaces || namespaces.test( handleObj.namespace ) ) && -- ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { -- eventType.splice( j--, 1 ); -- -- if ( handleObj.selector ) { -- eventType.delegateCount--; -- } -- if ( special.remove ) { -- special.remove.call( elem, handleObj ); -- } -- } -- } -- -- // Remove generic event handler if we removed something and no more handlers exist -- // (avoids potential for endless recursion during removal of special event handlers) -- if ( eventType.length === 0 && origCount !== eventType.length ) { -- if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { -- jQuery.removeEvent( elem, type, elemData.handle ); -- } -- -- delete events[ type ]; -- } -- } -- -- // Remove the expando if it's no longer used -- if ( jQuery.isEmptyObject( events ) ) { -- handle = elemData.handle; -- if ( handle ) { -- handle.elem = null; -- } -- -- // removeData also checks for emptiness and clears the expando if empty -- // so use it instead of delete -- jQuery.removeData( elem, [ "events", "handle" ], true ); -- } -- }, -- -- // Events that are safe to short-circuit if no handlers are attached. -- // Native DOM events should not be added, they may have inline handlers. -- customEvent: { -- "getData": true, -- "setData": true, -- "changeData": true -- }, -- -- trigger: function( event, data, elem, onlyHandlers ) { -- // Don't do events on text and comment nodes -- if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { -- return; -- } -- -- // Event object or event type -- var type = event.type || event, -- namespaces = [], -- cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType; -- -- // focus/blur morphs to focusin/out; ensure we're not firing them right now -- if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { -- return; -- } -- -- if ( type.indexOf( "!" ) >= 0 ) { -- // Exclusive events trigger only for the exact event (no namespaces) -- type = type.slice(0, -1); -- exclusive = true; -- } -- -- if ( type.indexOf( "." ) >= 0 ) { -- // Namespaced trigger; create a regexp to match event type in handle() -- namespaces = type.split("."); -- type = namespaces.shift(); -- namespaces.sort(); -- } -- -- if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { -- // No jQuery handlers for this event type, and it can't have inline handlers -- return; -- } -- -- // Caller can pass in an Event, Object, or just an event type string -- event = typeof event === "object" ? -- // jQuery.Event object -- event[ jQuery.expando ] ? event : -- // Object literal -- new jQuery.Event( type, event ) : -- // Just the event type (string) -- new jQuery.Event( type ); -- -- event.type = type; -- event.isTrigger = true; -- event.exclusive = exclusive; -- event.namespace = namespaces.join( "." ); -- event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null; -- ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; -- -- // Handle a global trigger -- if ( !elem ) { -- -- // TODO: Stop taunting the data cache; remove global events and always attach to document -- cache = jQuery.cache; -- for ( i in cache ) { -- if ( cache[ i ].events && cache[ i ].events[ type ] ) { -- jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); -- } -- } -- return; -- } -- -- // Clean up the event in case it is being reused -- event.result = undefined; -- if ( !event.target ) { -- event.target = elem; -- } -- -- // Clone any incoming data and prepend the event, creating the handler arg list -- data = data != null ? jQuery.makeArray( data ) : []; -- data.unshift( event ); -- -- // Allow special events to draw outside the lines -- special = jQuery.event.special[ type ] || {}; -- if ( special.trigger && special.trigger.apply( elem, data ) === false ) { -- return; -- } -- -- // Determine event propagation path in advance, per W3C events spec (#9951) -- // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) -- eventPath = [[ elem, special.bindType || type ]]; -- if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { -- -- bubbleType = special.delegateType || type; -- cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; -- old = null; -- for ( ; cur; cur = cur.parentNode ) { -- eventPath.push([ cur, bubbleType ]); -- old = cur; -- } -- -- // Only add window if we got to document (e.g., not plain obj or detached DOM) -- if ( old && old === elem.ownerDocument ) { -- eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); -- } -- } -- -- // Fire handlers on the event path -- for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { -- -- cur = eventPath[i][0]; -- event.type = eventPath[i][1]; -- -- handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); -- if ( handle ) { -- handle.apply( cur, data ); -- } -- // Note that this is a bare JS function and not a jQuery handler -- handle = ontype && cur[ ontype ]; -- if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) { -- event.preventDefault(); -- } -- } -- event.type = type; -- -- // If nobody prevented the default action, do it now -- if ( !onlyHandlers && !event.isDefaultPrevented() ) { -- -- if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && -- !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { -- -- // Call a native DOM method on the target with the same name name as the event. -- // Can't use an .isFunction() check here because IE6/7 fails that test. -- // Don't do default actions on window, that's where global variables be (#6170) -- // IE<9 dies on focus/blur to hidden element (#1486) -- if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { -- -- // Don't re-trigger an onFOO event when we call its FOO() method -- old = elem[ ontype ]; -- -- if ( old ) { -- elem[ ontype ] = null; -- } -- -- // Prevent re-triggering of the same event, since we already bubbled it above -- jQuery.event.triggered = type; -- elem[ type ](); -- jQuery.event.triggered = undefined; -- -- if ( old ) { -- elem[ ontype ] = old; -- } -- } -- } -- } -- -- return event.result; -- }, -- -- dispatch: function( event ) { -- -- // Make a writable jQuery.Event from the native event object -- event = jQuery.event.fix( event || window.event ); -- -- var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), -- delegateCount = handlers.delegateCount, -- args = [].slice.call( arguments, 0 ), -- run_all = !event.exclusive && !event.namespace, -- special = jQuery.event.special[ event.type ] || {}, -- handlerQueue = [], -- i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related; -- -- // Use the fix-ed jQuery.Event rather than the (read-only) native event -- args[0] = event; -- event.delegateTarget = this; -- -- // Call the preDispatch hook for the mapped type, and let it bail if desired -- if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { -- return; -- } -- -- // Determine handlers that should run if there are delegated events -- // Avoid non-left-click bubbling in Firefox (#3861) -- if ( delegateCount && !(event.button && event.type === "click") ) { -- -- // Pregenerate a single jQuery object for reuse with .is() -- jqcur = jQuery(this); -- jqcur.context = this.ownerDocument || this; -- -- for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { -- -- // Don't process events on disabled elements (#6911, #8165) -- if ( cur.disabled !== true ) { -- selMatch = {}; -- matches = []; -- jqcur[0] = cur; -- for ( i = 0; i < delegateCount; i++ ) { -- handleObj = handlers[ i ]; -- sel = handleObj.selector; -- -- if ( selMatch[ sel ] === undefined ) { -- selMatch[ sel ] = ( -- handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel ) -- ); -- } -- if ( selMatch[ sel ] ) { -- matches.push( handleObj ); -- } -- } -- if ( matches.length ) { -- handlerQueue.push({ elem: cur, matches: matches }); -- } -- } -- } -- } -- -- // Add the remaining (directly-bound) handlers -- if ( handlers.length > delegateCount ) { -- handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); -- } -- -- // Run delegates first; they may want to stop propagation beneath us -- for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { -- matched = handlerQueue[ i ]; -- event.currentTarget = matched.elem; -- -- for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { -- handleObj = matched.matches[ j ]; -- -- // Triggered event must either 1) be non-exclusive and have no namespace, or -- // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). -- if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { -- -- event.data = handleObj.data; -- event.handleObj = handleObj; -- -- ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) -- .apply( matched.elem, args ); -- -- if ( ret !== undefined ) { -- event.result = ret; -- if ( ret === false ) { -- event.preventDefault(); -- event.stopPropagation(); -- } -- } -- } -- } -- } -- -- // Call the postDispatch hook for the mapped type -- if ( special.postDispatch ) { -- special.postDispatch.call( this, event ); -- } -- -- return event.result; -- }, -- -- // Includes some event props shared by KeyEvent and MouseEvent -- // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** -- props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), -- -- fixHooks: {}, -- -- keyHooks: { -- props: "char charCode key keyCode".split(" "), -- filter: function( event, original ) { -- -- // Add which for key events -- if ( event.which == null ) { -- event.which = original.charCode != null ? original.charCode : original.keyCode; -- } -- -- return event; -- } -- }, -- -- mouseHooks: { -- props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), -- filter: function( event, original ) { -- var eventDoc, doc, body, -- button = original.button, -- fromElement = original.fromElement; -- -- // Calculate pageX/Y if missing and clientX/Y available -- if ( event.pageX == null && original.clientX != null ) { -- eventDoc = event.target.ownerDocument || document; -- doc = eventDoc.documentElement; -- body = eventDoc.body; -- -- event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); -- event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); -- } -- -- // Add relatedTarget, if necessary -- if ( !event.relatedTarget && fromElement ) { -- event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; -- } -- -- // Add which for click: 1 === left; 2 === middle; 3 === right -- // Note: button is not normalized, so don't use it -- if ( !event.which && button !== undefined ) { -- event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); -- } -- -- return event; -- } -- }, -- -- fix: function( event ) { -- if ( event[ jQuery.expando ] ) { -- return event; -- } -- -- // Create a writable copy of the event object and normalize some properties -- var i, prop, -- originalEvent = event, -- fixHook = jQuery.event.fixHooks[ event.type ] || {}, -- copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; -- -- event = jQuery.Event( originalEvent ); -- -- for ( i = copy.length; i; ) { -- prop = copy[ --i ]; -- event[ prop ] = originalEvent[ prop ]; -- } -- -- // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) -- if ( !event.target ) { -- event.target = originalEvent.srcElement || document; -- } -- -- // Target should not be a text node (#504, Safari) -- if ( event.target.nodeType === 3 ) { -- event.target = event.target.parentNode; -- } -- -- // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8) -- if ( event.metaKey === undefined ) { -- event.metaKey = event.ctrlKey; -- } -- -- return fixHook.filter? fixHook.filter( event, originalEvent ) : event; -- }, -- -- special: { -- ready: { -- // Make sure the ready event is setup -- setup: jQuery.bindReady -- }, -- -- load: { -- // Prevent triggered image.load events from bubbling to window.load -- noBubble: true -- }, -- -- focus: { -- delegateType: "focusin" -- }, -- blur: { -- delegateType: "focusout" -- }, -- -- beforeunload: { -- setup: function( data, namespaces, eventHandle ) { -- // We only want to do this special case on windows -- if ( jQuery.isWindow( this ) ) { -- this.onbeforeunload = eventHandle; -- } -- }, -- -- teardown: function( namespaces, eventHandle ) { -- if ( this.onbeforeunload === eventHandle ) { -- this.onbeforeunload = null; -- } -- } -- } -- }, -- -- simulate: function( type, elem, event, bubble ) { -- // Piggyback on a donor event to simulate a different one. -- // Fake originalEvent to avoid donor's stopPropagation, but if the -- // simulated event prevents default then we do the same on the donor. -- var e = jQuery.extend( -- new jQuery.Event(), -- event, -- { type: type, -- isSimulated: true, -- originalEvent: {} -- } -- ); -- if ( bubble ) { -- jQuery.event.trigger( e, null, elem ); -- } else { -- jQuery.event.dispatch.call( elem, e ); -- } -- if ( e.isDefaultPrevented() ) { -- event.preventDefault(); -- } -- } --}; -- --// Some plugins are using, but it's undocumented/deprecated and will be removed. --// The 1.7 special event interface should provide all the hooks needed now. --jQuery.event.handle = jQuery.event.dispatch; -- --jQuery.removeEvent = document.removeEventListener ? -- function( elem, type, handle ) { -- if ( elem.removeEventListener ) { -- elem.removeEventListener( type, handle, false ); -- } -- } : -- function( elem, type, handle ) { -- if ( elem.detachEvent ) { -- elem.detachEvent( "on" + type, handle ); -- } -- }; -- --jQuery.Event = function( src, props ) { -- // Allow instantiation without the 'new' keyword -- if ( !(this instanceof jQuery.Event) ) { -- return new jQuery.Event( src, props ); -- } -- -- // Event object -- if ( src && src.type ) { -- this.originalEvent = src; -- this.type = src.type; -- -- // Events bubbling up the document may have been marked as prevented -- // by a handler lower down the tree; reflect the correct value. -- this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || -- src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; -- -- // Event type -- } else { -- this.type = src; -- } -- -- // Put explicitly provided properties onto the event object -- if ( props ) { -- jQuery.extend( this, props ); -- } -- -- // Create a timestamp if incoming event doesn't have one -- this.timeStamp = src && src.timeStamp || jQuery.now(); -- -- // Mark it as fixed -- this[ jQuery.expando ] = true; --}; -- --function returnFalse() { -- return false; --} --function returnTrue() { -- return true; --} -- --// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding --// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html --jQuery.Event.prototype = { -- preventDefault: function() { -- this.isDefaultPrevented = returnTrue; -- -- var e = this.originalEvent; -- if ( !e ) { -- return; -- } -- -- // if preventDefault exists run it on the original event -- if ( e.preventDefault ) { -- e.preventDefault(); -- -- // otherwise set the returnValue property of the original event to false (IE) -- } else { -- e.returnValue = false; -- } -- }, -- stopPropagation: function() { -- this.isPropagationStopped = returnTrue; -- -- var e = this.originalEvent; -- if ( !e ) { -- return; -- } -- // if stopPropagation exists run it on the original event -- if ( e.stopPropagation ) { -- e.stopPropagation(); -- } -- // otherwise set the cancelBubble property of the original event to true (IE) -- e.cancelBubble = true; -- }, -- stopImmediatePropagation: function() { -- this.isImmediatePropagationStopped = returnTrue; -- this.stopPropagation(); -- }, -- isDefaultPrevented: returnFalse, -- isPropagationStopped: returnFalse, -- isImmediatePropagationStopped: returnFalse --}; -- --// Create mouseenter/leave events using mouseover/out and event-time checks --jQuery.each({ -- mouseenter: "mouseover", -- mouseleave: "mouseout" --}, function( orig, fix ) { -- jQuery.event.special[ orig ] = { -- delegateType: fix, -- bindType: fix, -- -- handle: function( event ) { -- var target = this, -- related = event.relatedTarget, -- handleObj = event.handleObj, -- selector = handleObj.selector, -- ret; -- -- // For mousenter/leave call the handler if related is outside the target. -- // NB: No relatedTarget if the mouse left/entered the browser window -- if ( !related || (related !== target && !jQuery.contains( target, related )) ) { -- event.type = handleObj.origType; -- ret = handleObj.handler.apply( this, arguments ); -- event.type = fix; -- } -- return ret; -- } -- }; --}); -- --// IE submit delegation --if ( !jQuery.support.submitBubbles ) { -- -- jQuery.event.special.submit = { -- setup: function() { -- // Only need this for delegated form submit events -- if ( jQuery.nodeName( this, "form" ) ) { -- return false; -- } -- -- // Lazy-add a submit handler when a descendant form may potentially be submitted -- jQuery.event.add( this, "click._submit keypress._submit", function( e ) { -- // Node name check avoids a VML-related crash in IE (#9807) -- var elem = e.target, -- form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; -- if ( form && !form._submit_attached ) { -- jQuery.event.add( form, "submit._submit", function( event ) { -- event._submit_bubble = true; -- }); -- form._submit_attached = true; -- } -- }); -- // return undefined since we don't need an event listener -- }, -- -- postDispatch: function( event ) { -- // If form was submitted by the user, bubble the event up the tree -- if ( event._submit_bubble ) { -- delete event._submit_bubble; -- if ( this.parentNode && !event.isTrigger ) { -- jQuery.event.simulate( "submit", this.parentNode, event, true ); -- } -- } -- }, -- -- teardown: function() { -- // Only need this for delegated form submit events -- if ( jQuery.nodeName( this, "form" ) ) { -- return false; -- } -- -- // Remove delegated handlers; cleanData eventually reaps submit handlers attached above -- jQuery.event.remove( this, "._submit" ); -- } -- }; --} -- --// IE change delegation and checkbox/radio fix --if ( !jQuery.support.changeBubbles ) { -- -- jQuery.event.special.change = { -- -- setup: function() { -- -- if ( rformElems.test( this.nodeName ) ) { -- // IE doesn't fire change on a check/radio until blur; trigger it on click -- // after a propertychange. Eat the blur-change in special.change.handle. -- // This still fires onchange a second time for check/radio after blur. -- if ( this.type === "checkbox" || this.type === "radio" ) { -- jQuery.event.add( this, "propertychange._change", function( event ) { -- if ( event.originalEvent.propertyName === "checked" ) { -- this._just_changed = true; -- } -- }); -- jQuery.event.add( this, "click._change", function( event ) { -- if ( this._just_changed && !event.isTrigger ) { -- this._just_changed = false; -- jQuery.event.simulate( "change", this, event, true ); -- } -- }); -- } -- return false; -- } -- // Delegated event; lazy-add a change handler on descendant inputs -- jQuery.event.add( this, "beforeactivate._change", function( e ) { -- var elem = e.target; -- -- if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) { -- jQuery.event.add( elem, "change._change", function( event ) { -- if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { -- jQuery.event.simulate( "change", this.parentNode, event, true ); -- } -- }); -- elem._change_attached = true; -- } -- }); -- }, -- -- handle: function( event ) { -- var elem = event.target; -- -- // Swallow native change events from checkbox/radio, we already triggered them above -- if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { -- return event.handleObj.handler.apply( this, arguments ); -- } -- }, -- -- teardown: function() { -- jQuery.event.remove( this, "._change" ); -- -- return rformElems.test( this.nodeName ); -- } -- }; --} -- --// Create "bubbling" focus and blur events --if ( !jQuery.support.focusinBubbles ) { -- jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { -- -- // Attach a single capturing handler while someone wants focusin/focusout -- var attaches = 0, -- handler = function( event ) { -- jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); -- }; -- -- jQuery.event.special[ fix ] = { -- setup: function() { -- if ( attaches++ === 0 ) { -- document.addEventListener( orig, handler, true ); -- } -- }, -- teardown: function() { -- if ( --attaches === 0 ) { -- document.removeEventListener( orig, handler, true ); -- } -- } -- }; -- }); --} -- --jQuery.fn.extend({ -- -- on: function( types, selector, data, fn, /*INTERNAL*/ one ) { -- var origFn, type; -- -- // Types can be a map of types/handlers -- if ( typeof types === "object" ) { -- // ( types-Object, selector, data ) -- if ( typeof selector !== "string" ) { // && selector != null -- // ( types-Object, data ) -- data = data || selector; -- selector = undefined; -- } -- for ( type in types ) { -- this.on( type, selector, data, types[ type ], one ); -- } -- return this; -- } -- -- if ( data == null && fn == null ) { -- // ( types, fn ) -- fn = selector; -- data = selector = undefined; -- } else if ( fn == null ) { -- if ( typeof selector === "string" ) { -- // ( types, selector, fn ) -- fn = data; -- data = undefined; -- } else { -- // ( types, data, fn ) -- fn = data; -- data = selector; -- selector = undefined; -- } -- } -- if ( fn === false ) { -- fn = returnFalse; -- } else if ( !fn ) { -- return this; -- } -- -- if ( one === 1 ) { -- origFn = fn; -- fn = function( event ) { -- // Can use an empty set, since event contains the info -- jQuery().off( event ); -- return origFn.apply( this, arguments ); -- }; -- // Use same guid so caller can remove using origFn -- fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); -- } -- return this.each( function() { -- jQuery.event.add( this, types, fn, data, selector ); -- }); -- }, -- one: function( types, selector, data, fn ) { -- return this.on( types, selector, data, fn, 1 ); -- }, -- off: function( types, selector, fn ) { -- if ( types && types.preventDefault && types.handleObj ) { -- // ( event ) dispatched jQuery.Event -- var handleObj = types.handleObj; -- jQuery( types.delegateTarget ).off( -- handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, -- handleObj.selector, -- handleObj.handler -- ); -- return this; -- } -- if ( typeof types === "object" ) { -- // ( types-object [, selector] ) -- for ( var type in types ) { -- this.off( type, selector, types[ type ] ); -- } -- return this; -- } -- if ( selector === false || typeof selector === "function" ) { -- // ( types [, fn] ) -- fn = selector; -- selector = undefined; -- } -- if ( fn === false ) { -- fn = returnFalse; -- } -- return this.each(function() { -- jQuery.event.remove( this, types, fn, selector ); -- }); -- }, -- -- bind: function( types, data, fn ) { -- return this.on( types, null, data, fn ); -- }, -- unbind: function( types, fn ) { -- return this.off( types, null, fn ); -- }, -- -- live: function( types, data, fn ) { -- jQuery( this.context ).on( types, this.selector, data, fn ); -- return this; -- }, -- die: function( types, fn ) { -- jQuery( this.context ).off( types, this.selector || "**", fn ); -- return this; -- }, -- -- delegate: function( selector, types, data, fn ) { -- return this.on( types, selector, data, fn ); -- }, -- undelegate: function( selector, types, fn ) { -- // ( namespace ) or ( selector, types [, fn] ) -- return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn ); -- }, -- -- trigger: function( type, data ) { -- return this.each(function() { -- jQuery.event.trigger( type, data, this ); -- }); -- }, -- triggerHandler: function( type, data ) { -- if ( this[0] ) { -- return jQuery.event.trigger( type, data, this[0], true ); -- } -- }, -- -- toggle: function( fn ) { -- // Save reference to arguments for access in closure -- var args = arguments, -- guid = fn.guid || jQuery.guid++, -- i = 0, -- toggler = function( event ) { -- // Figure out which function to execute -- var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; -- jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); -- -- // Make sure that clicks stop -- event.preventDefault(); -- -- // and execute the function -- return args[ lastToggle ].apply( this, arguments ) || false; -- }; -- -- // link all the functions, so any of them can unbind this click handler -- toggler.guid = guid; -- while ( i < args.length ) { -- args[ i++ ].guid = guid; -- } -- -- return this.click( toggler ); -- }, -- -- hover: function( fnOver, fnOut ) { -- return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); -- } --}); -- --jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + -- "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + -- "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { -- -- // Handle event binding -- jQuery.fn[ name ] = function( data, fn ) { -- if ( fn == null ) { -- fn = data; -- data = null; -- } -- -- return arguments.length > 0 ? -- this.on( name, null, data, fn ) : -- this.trigger( name ); -- }; -- -- if ( jQuery.attrFn ) { -- jQuery.attrFn[ name ] = true; -- } -- -- if ( rkeyEvent.test( name ) ) { -- jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; -- } -- -- if ( rmouseEvent.test( name ) ) { -- jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; -- } --}); -- -- -- --/*! -- * Sizzle CSS Selector Engine -- * Copyright 2011, The Dojo Foundation -- * Released under the MIT, BSD, and GPL Licenses. -- * More information: http://sizzlejs.com/ -- */ --(function(){ -- --var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, -- expando = "sizcache" + (Math.random() + '').replace('.', ''), -- done = 0, -- toString = Object.prototype.toString, -- hasDuplicate = false, -- baseHasDuplicate = true, -- rBackslash = /\\/g, -- rReturn = /\r\n/g, -- rNonWord = /\W/; -- --// Here we check if the JavaScript engine is using some sort of --// optimization where it does not always call our comparision --// function. If that is the case, discard the hasDuplicate value. --// Thus far that includes Google Chrome. --[0, 0].sort(function() { -- baseHasDuplicate = false; -- return 0; --}); -- --var Sizzle = function( selector, context, results, seed ) { -- results = results || []; -- context = context || document; -- -- var origContext = context; -- -- if ( context.nodeType !== 1 && context.nodeType !== 9 ) { -- return []; -- } -- -- if ( !selector || typeof selector !== "string" ) { -- return results; -- } -- -- var m, set, checkSet, extra, ret, cur, pop, i, -- prune = true, -- contextXML = Sizzle.isXML( context ), -- parts = [], -- soFar = selector; -- -- // Reset the position of the chunker regexp (start from head) -- do { -- chunker.exec( "" ); -- m = chunker.exec( soFar ); -- -- if ( m ) { -- soFar = m[3]; -- -- parts.push( m[1] ); -- -- if ( m[2] ) { -- extra = m[3]; -- break; -- } -- } -- } while ( m ); -- -- if ( parts.length > 1 && origPOS.exec( selector ) ) { -- -- if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { -- set = posProcess( parts[0] + parts[1], context, seed ); -- -- } else { -- set = Expr.relative[ parts[0] ] ? -- [ context ] : -- Sizzle( parts.shift(), context ); -- -- while ( parts.length ) { -- selector = parts.shift(); -- -- if ( Expr.relative[ selector ] ) { -- selector += parts.shift(); -- } -- -- set = posProcess( selector, set, seed ); -- } -- } -- -- } else { -- // Take a shortcut and set the context if the root selector is an ID -- // (but not if it'll be faster if the inner selector is an ID) -- if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && -- Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { -- -- ret = Sizzle.find( parts.shift(), context, contextXML ); -- context = ret.expr ? -- Sizzle.filter( ret.expr, ret.set )[0] : -- ret.set[0]; -- } -- -- if ( context ) { -- ret = seed ? -- { expr: parts.pop(), set: makeArray(seed) } : -- Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); -- -- set = ret.expr ? -- Sizzle.filter( ret.expr, ret.set ) : -- ret.set; -- -- if ( parts.length > 0 ) { -- checkSet = makeArray( set ); -- -- } else { -- prune = false; -- } -- -- while ( parts.length ) { -- cur = parts.pop(); -- pop = cur; -- -- if ( !Expr.relative[ cur ] ) { -- cur = ""; -- } else { -- pop = parts.pop(); -- } -- -- if ( pop == null ) { -- pop = context; -- } -- -- Expr.relative[ cur ]( checkSet, pop, contextXML ); -- } -- -- } else { -- checkSet = parts = []; -- } -- } -- -- if ( !checkSet ) { -- checkSet = set; -- } -- -- if ( !checkSet ) { -- Sizzle.error( cur || selector ); -- } -- -- if ( toString.call(checkSet) === "[object Array]" ) { -- if ( !prune ) { -- results.push.apply( results, checkSet ); -- -- } else if ( context && context.nodeType === 1 ) { -- for ( i = 0; checkSet[i] != null; i++ ) { -- if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { -- results.push( set[i] ); -- } -- } -- -- } else { -- for ( i = 0; checkSet[i] != null; i++ ) { -- if ( checkSet[i] && checkSet[i].nodeType === 1 ) { -- results.push( set[i] ); -- } -- } -- } -- -- } else { -- makeArray( checkSet, results ); -- } -- -- if ( extra ) { -- Sizzle( extra, origContext, results, seed ); -- Sizzle.uniqueSort( results ); -- } -- -- return results; --}; -- --Sizzle.uniqueSort = function( results ) { -- if ( sortOrder ) { -- hasDuplicate = baseHasDuplicate; -- results.sort( sortOrder ); -- -- if ( hasDuplicate ) { -- for ( var i = 1; i < results.length; i++ ) { -- if ( results[i] === results[ i - 1 ] ) { -- results.splice( i--, 1 ); -- } -- } -- } -- } -- -- return results; --}; -- --Sizzle.matches = function( expr, set ) { -- return Sizzle( expr, null, null, set ); --}; -- --Sizzle.matchesSelector = function( node, expr ) { -- return Sizzle( expr, null, null, [node] ).length > 0; --}; -- --Sizzle.find = function( expr, context, isXML ) { -- var set, i, len, match, type, left; -- -- if ( !expr ) { -- return []; -- } -- -- for ( i = 0, len = Expr.order.length; i < len; i++ ) { -- type = Expr.order[i]; -- -- if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { -- left = match[1]; -- match.splice( 1, 1 ); -- -- if ( left.substr( left.length - 1 ) !== "\\" ) { -- match[1] = (match[1] || "").replace( rBackslash, "" ); -- set = Expr.find[ type ]( match, context, isXML ); -- -- if ( set != null ) { -- expr = expr.replace( Expr.match[ type ], "" ); -- break; -- } -- } -- } -- } -- -- if ( !set ) { -- set = typeof context.getElementsByTagName !== "undefined" ? -- context.getElementsByTagName( "*" ) : -- []; -- } -- -- return { set: set, expr: expr }; --}; -- --Sizzle.filter = function( expr, set, inplace, not ) { -- var match, anyFound, -- type, found, item, filter, left, -- i, pass, -- old = expr, -- result = [], -- curLoop = set, -- isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); -- -- while ( expr && set.length ) { -- for ( type in Expr.filter ) { -- if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { -- filter = Expr.filter[ type ]; -- left = match[1]; -- -- anyFound = false; -- -- match.splice(1,1); -- -- if ( left.substr( left.length - 1 ) === "\\" ) { -- continue; -- } -- -- if ( curLoop === result ) { -- result = []; -- } -- -- if ( Expr.preFilter[ type ] ) { -- match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); -- -- if ( !match ) { -- anyFound = found = true; -- -- } else if ( match === true ) { -- continue; -- } -- } -- -- if ( match ) { -- for ( i = 0; (item = curLoop[i]) != null; i++ ) { -- if ( item ) { -- found = filter( item, match, i, curLoop ); -- pass = not ^ found; -- -- if ( inplace && found != null ) { -- if ( pass ) { -- anyFound = true; -- -- } else { -- curLoop[i] = false; -- } -- -- } else if ( pass ) { -- result.push( item ); -- anyFound = true; -- } -- } -- } -- } -- -- if ( found !== undefined ) { -- if ( !inplace ) { -- curLoop = result; -- } -- -- expr = expr.replace( Expr.match[ type ], "" ); -- -- if ( !anyFound ) { -- return []; -- } -- -- break; -- } -- } -- } -- -- // Improper expression -- if ( expr === old ) { -- if ( anyFound == null ) { -- Sizzle.error( expr ); -- -- } else { -- break; -- } -- } -- -- old = expr; -- } -- -- return curLoop; --}; -- --Sizzle.error = function( msg ) { -- throw new Error( "Syntax error, unrecognized expression: " + msg ); --}; -- --/** -- * Utility function for retreiving the text value of an array of DOM nodes -- * @param {Array|Element} elem -- */ --var getText = Sizzle.getText = function( elem ) { -- var i, node, -- nodeType = elem.nodeType, -- ret = ""; -- -- if ( nodeType ) { -- if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { -- // Use textContent || innerText for elements -- if ( typeof elem.textContent === 'string' ) { -- return elem.textContent; -- } else if ( typeof elem.innerText === 'string' ) { -- // Replace IE's carriage returns -- return elem.innerText.replace( rReturn, '' ); -- } else { -- // Traverse it's children -- for ( elem = elem.firstChild; elem; elem = elem.nextSibling) { -- ret += getText( elem ); -- } -- } -- } else if ( nodeType === 3 || nodeType === 4 ) { -- return elem.nodeValue; -- } -- } else { -- -- // If no nodeType, this is expected to be an array -- for ( i = 0; (node = elem[i]); i++ ) { -- // Do not traverse comment nodes -- if ( node.nodeType !== 8 ) { -- ret += getText( node ); -- } -- } -- } -- return ret; --}; -- --var Expr = Sizzle.selectors = { -- order: [ "ID", "NAME", "TAG" ], -- -- match: { -- ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, -- CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, -- NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, -- ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, -- TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, -- CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, -- POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, -- PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ -- }, -- -- leftMatch: {}, -- -- attrMap: { -- "class": "className", -- "for": "htmlFor" -- }, -- -- attrHandle: { -- href: function( elem ) { -- return elem.getAttribute( "href" ); -- }, -- type: function( elem ) { -- return elem.getAttribute( "type" ); -- } -- }, -- -- relative: { -- "+": function(checkSet, part){ -- var isPartStr = typeof part === "string", -- isTag = isPartStr && !rNonWord.test( part ), -- isPartStrNotTag = isPartStr && !isTag; -- -- if ( isTag ) { -- part = part.toLowerCase(); -- } -- -- for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { -- if ( (elem = checkSet[i]) ) { -- while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} -- -- checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? -- elem || false : -- elem === part; -- } -- } -- -- if ( isPartStrNotTag ) { -- Sizzle.filter( part, checkSet, true ); -- } -- }, -- -- ">": function( checkSet, part ) { -- var elem, -- isPartStr = typeof part === "string", -- i = 0, -- l = checkSet.length; -- -- if ( isPartStr && !rNonWord.test( part ) ) { -- part = part.toLowerCase(); -- -- for ( ; i < l; i++ ) { -- elem = checkSet[i]; -- -- if ( elem ) { -- var parent = elem.parentNode; -- checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; -- } -- } -- -- } else { -- for ( ; i < l; i++ ) { -- elem = checkSet[i]; -- -- if ( elem ) { -- checkSet[i] = isPartStr ? -- elem.parentNode : -- elem.parentNode === part; -- } -- } -- -- if ( isPartStr ) { -- Sizzle.filter( part, checkSet, true ); -- } -- } -- }, -- -- "": function(checkSet, part, isXML){ -- var nodeCheck, -- doneName = done++, -- checkFn = dirCheck; -- -- if ( typeof part === "string" && !rNonWord.test( part ) ) { -- part = part.toLowerCase(); -- nodeCheck = part; -- checkFn = dirNodeCheck; -- } -- -- checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); -- }, -- -- "~": function( checkSet, part, isXML ) { -- var nodeCheck, -- doneName = done++, -- checkFn = dirCheck; -- -- if ( typeof part === "string" && !rNonWord.test( part ) ) { -- part = part.toLowerCase(); -- nodeCheck = part; -- checkFn = dirNodeCheck; -- } -- -- checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); -- } -- }, -- -- find: { -- ID: function( match, context, isXML ) { -- if ( typeof context.getElementById !== "undefined" && !isXML ) { -- var m = context.getElementById(match[1]); -- // Check parentNode to catch when Blackberry 4.6 returns -- // nodes that are no longer in the document #6963 -- return m && m.parentNode ? [m] : []; -- } -- }, -- -- NAME: function( match, context ) { -- if ( typeof context.getElementsByName !== "undefined" ) { -- var ret = [], -- results = context.getElementsByName( match[1] ); -- -- for ( var i = 0, l = results.length; i < l; i++ ) { -- if ( results[i].getAttribute("name") === match[1] ) { -- ret.push( results[i] ); -- } -- } -- -- return ret.length === 0 ? null : ret; -- } -- }, -- -- TAG: function( match, context ) { -- if ( typeof context.getElementsByTagName !== "undefined" ) { -- return context.getElementsByTagName( match[1] ); -- } -- } -- }, -- preFilter: { -- CLASS: function( match, curLoop, inplace, result, not, isXML ) { -- match = " " + match[1].replace( rBackslash, "" ) + " "; -- -- if ( isXML ) { -- return match; -- } -- -- for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { -- if ( elem ) { -- if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { -- if ( !inplace ) { -- result.push( elem ); -- } -- -- } else if ( inplace ) { -- curLoop[i] = false; -- } -- } -- } -- -- return false; -- }, -- -- ID: function( match ) { -- return match[1].replace( rBackslash, "" ); -- }, -- -- TAG: function( match, curLoop ) { -- return match[1].replace( rBackslash, "" ).toLowerCase(); -- }, -- -- CHILD: function( match ) { -- if ( match[1] === "nth" ) { -- if ( !match[2] ) { -- Sizzle.error( match[0] ); -- } -- -- match[2] = match[2].replace(/^\+|\s*/g, ''); -- -- // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' -- var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( -- match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || -- !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); -- -- // calculate the numbers (first)n+(last) including if they are negative -- match[2] = (test[1] + (test[2] || 1)) - 0; -- match[3] = test[3] - 0; -- } -- else if ( match[2] ) { -- Sizzle.error( match[0] ); -- } -- -- // TODO: Move to normal caching system -- match[0] = done++; -- -- return match; -- }, -- -- ATTR: function( match, curLoop, inplace, result, not, isXML ) { -- var name = match[1] = match[1].replace( rBackslash, "" ); -- -- if ( !isXML && Expr.attrMap[name] ) { -- match[1] = Expr.attrMap[name]; -- } -- -- // Handle if an un-quoted value was used -- match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); -- -- if ( match[2] === "~=" ) { -- match[4] = " " + match[4] + " "; -- } -- -- return match; -- }, -- -- PSEUDO: function( match, curLoop, inplace, result, not ) { -- if ( match[1] === "not" ) { -- // If we're dealing with a complex expression, or a simple one -- if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { -- match[3] = Sizzle(match[3], null, null, curLoop); -- -- } else { -- var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); -- -- if ( !inplace ) { -- result.push.apply( result, ret ); -- } -- -- return false; -- } -- -- } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { -- return true; -- } -- -- return match; -- }, -- -- POS: function( match ) { -- match.unshift( true ); -- -- return match; -- } -- }, -- -- filters: { -- enabled: function( elem ) { -- return elem.disabled === false && elem.type !== "hidden"; -- }, -- -- disabled: function( elem ) { -- return elem.disabled === true; -- }, -- -- checked: function( elem ) { -- return elem.checked === true; -- }, -- -- selected: function( elem ) { -- // Accessing this property makes selected-by-default -- // options in Safari work properly -- if ( elem.parentNode ) { -- elem.parentNode.selectedIndex; -- } -- -- return elem.selected === true; -- }, -- -- parent: function( elem ) { -- return !!elem.firstChild; -- }, -- -- empty: function( elem ) { -- return !elem.firstChild; -- }, -- -- has: function( elem, i, match ) { -- return !!Sizzle( match[3], elem ).length; -- }, -- -- header: function( elem ) { -- return (/h\d/i).test( elem.nodeName ); -- }, -- -- text: function( elem ) { -- var attr = elem.getAttribute( "type" ), type = elem.type; -- // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) -- // use getAttribute instead to test this case -- return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); -- }, -- -- radio: function( elem ) { -- return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; -- }, -- -- checkbox: function( elem ) { -- return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; -- }, -- -- file: function( elem ) { -- return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; -- }, -- -- password: function( elem ) { -- return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; -- }, -- -- submit: function( elem ) { -- var name = elem.nodeName.toLowerCase(); -- return (name === "input" || name === "button") && "submit" === elem.type; -- }, -- -- image: function( elem ) { -- return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; -- }, -- -- reset: function( elem ) { -- var name = elem.nodeName.toLowerCase(); -- return (name === "input" || name === "button") && "reset" === elem.type; -- }, -- -- button: function( elem ) { -- var name = elem.nodeName.toLowerCase(); -- return name === "input" && "button" === elem.type || name === "button"; -- }, -- -- input: function( elem ) { -- return (/input|select|textarea|button/i).test( elem.nodeName ); -- }, -- -- focus: function( elem ) { -- return elem === elem.ownerDocument.activeElement; -- } -- }, -- setFilters: { -- first: function( elem, i ) { -- return i === 0; -- }, -- -- last: function( elem, i, match, array ) { -- return i === array.length - 1; -- }, -- -- even: function( elem, i ) { -- return i % 2 === 0; -- }, -- -- odd: function( elem, i ) { -- return i % 2 === 1; -- }, -- -- lt: function( elem, i, match ) { -- return i < match[3] - 0; -- }, -- -- gt: function( elem, i, match ) { -- return i > match[3] - 0; -- }, -- -- nth: function( elem, i, match ) { -- return match[3] - 0 === i; -- }, -- -- eq: function( elem, i, match ) { -- return match[3] - 0 === i; -- } -- }, -- filter: { -- PSEUDO: function( elem, match, i, array ) { -- var name = match[1], -- filter = Expr.filters[ name ]; -- -- if ( filter ) { -- return filter( elem, i, match, array ); -- -- } else if ( name === "contains" ) { -- return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; -- -- } else if ( name === "not" ) { -- var not = match[3]; -- -- for ( var j = 0, l = not.length; j < l; j++ ) { -- if ( not[j] === elem ) { -- return false; -- } -- } -- -- return true; -- -- } else { -- Sizzle.error( name ); -- } -- }, -- -- CHILD: function( elem, match ) { -- var first, last, -- doneName, parent, cache, -- count, diff, -- type = match[1], -- node = elem; -- -- switch ( type ) { -- case "only": -- case "first": -- while ( (node = node.previousSibling) ) { -- if ( node.nodeType === 1 ) { -- return false; -- } -- } -- -- if ( type === "first" ) { -- return true; -- } -- -- node = elem; -- -- /* falls through */ -- case "last": -- while ( (node = node.nextSibling) ) { -- if ( node.nodeType === 1 ) { -- return false; -- } -- } -- -- return true; -- -- case "nth": -- first = match[2]; -- last = match[3]; -- -- if ( first === 1 && last === 0 ) { -- return true; -- } -- -- doneName = match[0]; -- parent = elem.parentNode; -- -- if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) { -- count = 0; -- -- for ( node = parent.firstChild; node; node = node.nextSibling ) { -- if ( node.nodeType === 1 ) { -- node.nodeIndex = ++count; -- } -- } -- -- parent[ expando ] = doneName; -- } -- -- diff = elem.nodeIndex - last; -- -- if ( first === 0 ) { -- return diff === 0; -- -- } else { -- return ( diff % first === 0 && diff / first >= 0 ); -- } -- } -- }, -- -- ID: function( elem, match ) { -- return elem.nodeType === 1 && elem.getAttribute("id") === match; -- }, -- -- TAG: function( elem, match ) { -- return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match; -- }, -- -- CLASS: function( elem, match ) { -- return (" " + (elem.className || elem.getAttribute("class")) + " ") -- .indexOf( match ) > -1; -- }, -- -- ATTR: function( elem, match ) { -- var name = match[1], -- result = Sizzle.attr ? -- Sizzle.attr( elem, name ) : -- Expr.attrHandle[ name ] ? -- Expr.attrHandle[ name ]( elem ) : -- elem[ name ] != null ? -- elem[ name ] : -- elem.getAttribute( name ), -- value = result + "", -- type = match[2], -- check = match[4]; -- -- return result == null ? -- type === "!=" : -- !type && Sizzle.attr ? -- result != null : -- type === "=" ? -- value === check : -- type === "*=" ? -- value.indexOf(check) >= 0 : -- type === "~=" ? -- (" " + value + " ").indexOf(check) >= 0 : -- !check ? -- value && result !== false : -- type === "!=" ? -- value !== check : -- type === "^=" ? -- value.indexOf(check) === 0 : -- type === "$=" ? -- value.substr(value.length - check.length) === check : -- type === "|=" ? -- value === check || value.substr(0, check.length + 1) === check + "-" : -- false; -- }, -- -- POS: function( elem, match, i, array ) { -- var name = match[2], -- filter = Expr.setFilters[ name ]; -- -- if ( filter ) { -- return filter( elem, i, match, array ); -- } -- } -- } --}; -- --var origPOS = Expr.match.POS, -- fescape = function(all, num){ -- return "\\" + (num - 0 + 1); -- }; -- --for ( var type in Expr.match ) { -- Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); -- Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); --} --// Expose origPOS --// "global" as in regardless of relation to brackets/parens --Expr.match.globalPOS = origPOS; -- --var makeArray = function( array, results ) { -- array = Array.prototype.slice.call( array, 0 ); -- -- if ( results ) { -- results.push.apply( results, array ); -- return results; -- } -- -- return array; --}; -- --// Perform a simple check to determine if the browser is capable of --// converting a NodeList to an array using builtin methods. --// Also verifies that the returned array holds DOM nodes --// (which is not the case in the Blackberry browser) --try { -- Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; -- --// Provide a fallback method if it does not work --} catch( e ) { -- makeArray = function( array, results ) { -- var i = 0, -- ret = results || []; -- -- if ( toString.call(array) === "[object Array]" ) { -- Array.prototype.push.apply( ret, array ); -- -- } else { -- if ( typeof array.length === "number" ) { -- for ( var l = array.length; i < l; i++ ) { -- ret.push( array[i] ); -- } -- -- } else { -- for ( ; array[i]; i++ ) { -- ret.push( array[i] ); -- } -- } -- } -- -- return ret; -- }; --} -- --var sortOrder, siblingCheck; -- --if ( document.documentElement.compareDocumentPosition ) { -- sortOrder = function( a, b ) { -- if ( a === b ) { -- hasDuplicate = true; -- return 0; -- } -- -- if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { -- return a.compareDocumentPosition ? -1 : 1; -- } -- -- return a.compareDocumentPosition(b) & 4 ? -1 : 1; -- }; -- --} else { -- sortOrder = function( a, b ) { -- // The nodes are identical, we can exit early -- if ( a === b ) { -- hasDuplicate = true; -- return 0; -- -- // Fallback to using sourceIndex (in IE) if it's available on both nodes -- } else if ( a.sourceIndex && b.sourceIndex ) { -- return a.sourceIndex - b.sourceIndex; -- } -- -- var al, bl, -- ap = [], -- bp = [], -- aup = a.parentNode, -- bup = b.parentNode, -- cur = aup; -- -- // If the nodes are siblings (or identical) we can do a quick check -- if ( aup === bup ) { -- return siblingCheck( a, b ); -- -- // If no parents were found then the nodes are disconnected -- } else if ( !aup ) { -- return -1; -- -- } else if ( !bup ) { -- return 1; -- } -- -- // Otherwise they're somewhere else in the tree so we need -- // to build up a full list of the parentNodes for comparison -- while ( cur ) { -- ap.unshift( cur ); -- cur = cur.parentNode; -- } -- -- cur = bup; -- -- while ( cur ) { -- bp.unshift( cur ); -- cur = cur.parentNode; -- } -- -- al = ap.length; -- bl = bp.length; -- -- // Start walking down the tree looking for a discrepancy -- for ( var i = 0; i < al && i < bl; i++ ) { -- if ( ap[i] !== bp[i] ) { -- return siblingCheck( ap[i], bp[i] ); -- } -- } -- -- // We ended someplace up the tree so do a sibling check -- return i === al ? -- siblingCheck( a, bp[i], -1 ) : -- siblingCheck( ap[i], b, 1 ); -- }; -- -- siblingCheck = function( a, b, ret ) { -- if ( a === b ) { -- return ret; -- } -- -- var cur = a.nextSibling; -- -- while ( cur ) { -- if ( cur === b ) { -- return -1; -- } -- -- cur = cur.nextSibling; -- } -- -- return 1; -- }; --} -- --// Check to see if the browser returns elements by name when --// querying by getElementById (and provide a workaround) --(function(){ -- // We're going to inject a fake input element with a specified name -- var form = document.createElement("div"), -- id = "script" + (new Date()).getTime(), -- root = document.documentElement; -- -- form.innerHTML = ""; -- -- // Inject it into the root element, check its status, and remove it quickly -- root.insertBefore( form, root.firstChild ); -- -- // The workaround has to do additional checks after a getElementById -- // Which slows things down for other browsers (hence the branching) -- if ( document.getElementById( id ) ) { -- Expr.find.ID = function( match, context, isXML ) { -- if ( typeof context.getElementById !== "undefined" && !isXML ) { -- var m = context.getElementById(match[1]); -- -- return m ? -- m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? -- [m] : -- undefined : -- []; -- } -- }; -- -- Expr.filter.ID = function( elem, match ) { -- var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); -- -- return elem.nodeType === 1 && node && node.nodeValue === match; -- }; -- } -- -- root.removeChild( form ); -- -- // release memory in IE -- root = form = null; --})(); -- --(function(){ -- // Check to see if the browser returns only elements -- // when doing getElementsByTagName("*") -- -- // Create a fake element -- var div = document.createElement("div"); -- div.appendChild( document.createComment("") ); -- -- // Make sure no comments are found -- if ( div.getElementsByTagName("*").length > 0 ) { -- Expr.find.TAG = function( match, context ) { -- var results = context.getElementsByTagName( match[1] ); -- -- // Filter out possible comments -- if ( match[1] === "*" ) { -- var tmp = []; -- -- for ( var i = 0; results[i]; i++ ) { -- if ( results[i].nodeType === 1 ) { -- tmp.push( results[i] ); -- } -- } -- -- results = tmp; -- } -- -- return results; -- }; -- } -- -- // Check to see if an attribute returns normalized href attributes -- div.innerHTML = ""; -- -- if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && -- div.firstChild.getAttribute("href") !== "#" ) { -- -- Expr.attrHandle.href = function( elem ) { -- return elem.getAttribute( "href", 2 ); -- }; -- } -- -- // release memory in IE -- div = null; --})(); -- --if ( document.querySelectorAll ) { -- (function(){ -- var oldSizzle = Sizzle, -- div = document.createElement("div"), -- id = "__sizzle__"; -- -- div.innerHTML = "

"; -- -- // Safari can't handle uppercase or unicode characters when -- // in quirks mode. -- if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { -- return; -- } -- -- Sizzle = function( query, context, extra, seed ) { -- context = context || document; -- -- // Only use querySelectorAll on non-XML documents -- // (ID selectors don't work in non-HTML documents) -- if ( !seed && !Sizzle.isXML(context) ) { -- // See if we find a selector to speed up -- var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); -- -- if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { -- // Speed-up: Sizzle("TAG") -- if ( match[1] ) { -- return makeArray( context.getElementsByTagName( query ), extra ); -- -- // Speed-up: Sizzle(".CLASS") -- } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { -- return makeArray( context.getElementsByClassName( match[2] ), extra ); -- } -- } -- -- if ( context.nodeType === 9 ) { -- // Speed-up: Sizzle("body") -- // The body element only exists once, optimize finding it -- if ( query === "body" && context.body ) { -- return makeArray( [ context.body ], extra ); -- -- // Speed-up: Sizzle("#ID") -- } else if ( match && match[3] ) { -- var elem = context.getElementById( match[3] ); -- -- // Check parentNode to catch when Blackberry 4.6 returns -- // nodes that are no longer in the document #6963 -- if ( elem && elem.parentNode ) { -- // Handle the case where IE and Opera return items -- // by name instead of ID -- if ( elem.id === match[3] ) { -- return makeArray( [ elem ], extra ); -- } -- -- } else { -- return makeArray( [], extra ); -- } -- } -- -- try { -- return makeArray( context.querySelectorAll(query), extra ); -- } catch(qsaError) {} -- -- // qSA works strangely on Element-rooted queries -- // We can work around this by specifying an extra ID on the root -- // and working up from there (Thanks to Andrew Dupont for the technique) -- // IE 8 doesn't work on object elements -- } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { -- var oldContext = context, -- old = context.getAttribute( "id" ), -- nid = old || id, -- hasParent = context.parentNode, -- relativeHierarchySelector = /^\s*[+~]/.test( query ); -- -- if ( !old ) { -- context.setAttribute( "id", nid ); -- } else { -- nid = nid.replace( /'/g, "\\$&" ); -- } -- if ( relativeHierarchySelector && hasParent ) { -- context = context.parentNode; -- } -- -- try { -- if ( !relativeHierarchySelector || hasParent ) { -- return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); -- } -- -- } catch(pseudoError) { -- } finally { -- if ( !old ) { -- oldContext.removeAttribute( "id" ); -- } -- } -- } -- } -- -- return oldSizzle(query, context, extra, seed); -- }; -- -- for ( var prop in oldSizzle ) { -- Sizzle[ prop ] = oldSizzle[ prop ]; -- } -- -- // release memory in IE -- div = null; -- })(); --} -- --(function(){ -- var html = document.documentElement, -- matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; -- -- if ( matches ) { -- // Check to see if it's possible to do matchesSelector -- // on a disconnected node (IE 9 fails this) -- var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), -- pseudoWorks = false; -- -- try { -- // This should fail with an exception -- // Gecko does not error, returns false instead -- matches.call( document.documentElement, "[test!='']:sizzle" ); -- -- } catch( pseudoError ) { -- pseudoWorks = true; -- } -- -- Sizzle.matchesSelector = function( node, expr ) { -- // Make sure that attribute selectors are quoted -- expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); -- -- if ( !Sizzle.isXML( node ) ) { -- try { -- if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { -- var ret = matches.call( node, expr ); -- -- // IE 9's matchesSelector returns false on disconnected nodes -- if ( ret || !disconnectedMatch || -- // As well, disconnected nodes are said to be in a document -- // fragment in IE 9, so check for that -- node.document && node.document.nodeType !== 11 ) { -- return ret; -- } -- } -- } catch(e) {} -- } -- -- return Sizzle(expr, null, null, [node]).length > 0; -- }; -- } --})(); -- --(function(){ -- var div = document.createElement("div"); -- -- div.innerHTML = "
"; -- -- // Opera can't find a second classname (in 9.6) -- // Also, make sure that getElementsByClassName actually exists -- if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { -- return; -- } -- -- // Safari caches class attributes, doesn't catch changes (in 3.2) -- div.lastChild.className = "e"; -- -- if ( div.getElementsByClassName("e").length === 1 ) { -- return; -- } -- -- Expr.order.splice(1, 0, "CLASS"); -- Expr.find.CLASS = function( match, context, isXML ) { -- if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { -- return context.getElementsByClassName(match[1]); -- } -- }; -- -- // release memory in IE -- div = null; --})(); -- --function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { -- for ( var i = 0, l = checkSet.length; i < l; i++ ) { -- var elem = checkSet[i]; -- -- if ( elem ) { -- var match = false; -- -- elem = elem[dir]; -- -- while ( elem ) { -- if ( elem[ expando ] === doneName ) { -- match = checkSet[elem.sizset]; -- break; -- } -- -- if ( elem.nodeType === 1 && !isXML ){ -- elem[ expando ] = doneName; -- elem.sizset = i; -- } -- -- if ( elem.nodeName.toLowerCase() === cur ) { -- match = elem; -- break; -- } -- -- elem = elem[dir]; -- } -- -- checkSet[i] = match; -- } -- } --} -- --function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { -- for ( var i = 0, l = checkSet.length; i < l; i++ ) { -- var elem = checkSet[i]; -- -- if ( elem ) { -- var match = false; -- -- elem = elem[dir]; -- -- while ( elem ) { -- if ( elem[ expando ] === doneName ) { -- match = checkSet[elem.sizset]; -- break; -- } -- -- if ( elem.nodeType === 1 ) { -- if ( !isXML ) { -- elem[ expando ] = doneName; -- elem.sizset = i; -- } -- -- if ( typeof cur !== "string" ) { -- if ( elem === cur ) { -- match = true; -- break; -- } -- -- } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { -- match = elem; -- break; -- } -- } -- -- elem = elem[dir]; -- } -- -- checkSet[i] = match; -- } -- } --} -- --if ( document.documentElement.contains ) { -- Sizzle.contains = function( a, b ) { -- return a !== b && (a.contains ? a.contains(b) : true); -- }; -- --} else if ( document.documentElement.compareDocumentPosition ) { -- Sizzle.contains = function( a, b ) { -- return !!(a.compareDocumentPosition(b) & 16); -- }; -- --} else { -- Sizzle.contains = function() { -- return false; -- }; --} -- --Sizzle.isXML = function( elem ) { -- // documentElement is verified for cases where it doesn't yet exist -- // (such as loading iframes in IE - #4833) -- var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; -- -- return documentElement ? documentElement.nodeName !== "HTML" : false; --}; -- --var posProcess = function( selector, context, seed ) { -- var match, -- tmpSet = [], -- later = "", -- root = context.nodeType ? [context] : context; -- -- // Position selectors must be done after the filter -- // And so must :not(positional) so we move all PSEUDOs to the end -- while ( (match = Expr.match.PSEUDO.exec( selector )) ) { -- later += match[0]; -- selector = selector.replace( Expr.match.PSEUDO, "" ); -- } -- -- selector = Expr.relative[selector] ? selector + "*" : selector; -- -- for ( var i = 0, l = root.length; i < l; i++ ) { -- Sizzle( selector, root[i], tmpSet, seed ); -- } -- -- return Sizzle.filter( later, tmpSet ); --}; -- --// EXPOSE --// Override sizzle attribute retrieval --Sizzle.attr = jQuery.attr; --Sizzle.selectors.attrMap = {}; --jQuery.find = Sizzle; --jQuery.expr = Sizzle.selectors; --jQuery.expr[":"] = jQuery.expr.filters; --jQuery.unique = Sizzle.uniqueSort; --jQuery.text = Sizzle.getText; --jQuery.isXMLDoc = Sizzle.isXML; --jQuery.contains = Sizzle.contains; -- -- --})(); -- -- --var runtil = /Until$/, -- rparentsprev = /^(?:parents|prevUntil|prevAll)/, -- // Note: This RegExp should be improved, or likely pulled from Sizzle -- rmultiselector = /,/, -- isSimple = /^.[^:#\[\.,]*$/, -- slice = Array.prototype.slice, -- POS = jQuery.expr.match.globalPOS, -- // methods guaranteed to produce a unique set when starting from a unique set -- guaranteedUnique = { -- children: true, -- contents: true, -- next: true, -- prev: true -- }; -- --jQuery.fn.extend({ -- find: function( selector ) { -- var self = this, -- i, l; -- -- if ( typeof selector !== "string" ) { -- return jQuery( selector ).filter(function() { -- for ( i = 0, l = self.length; i < l; i++ ) { -- if ( jQuery.contains( self[ i ], this ) ) { -- return true; -- } -- } -- }); -- } -- -- var ret = this.pushStack( "", "find", selector ), -- length, n, r; -- -- for ( i = 0, l = this.length; i < l; i++ ) { -- length = ret.length; -- jQuery.find( selector, this[i], ret ); -- -- if ( i > 0 ) { -- // Make sure that the results are unique -- for ( n = length; n < ret.length; n++ ) { -- for ( r = 0; r < length; r++ ) { -- if ( ret[r] === ret[n] ) { -- ret.splice(n--, 1); -- break; -- } -- } -- } -- } -- } -- -- return ret; -- }, -- -- has: function( target ) { -- var targets = jQuery( target ); -- return this.filter(function() { -- for ( var i = 0, l = targets.length; i < l; i++ ) { -- if ( jQuery.contains( this, targets[i] ) ) { -- return true; -- } -- } -- }); -- }, -- -- not: function( selector ) { -- return this.pushStack( winnow(this, selector, false), "not", selector); -- }, -- -- filter: function( selector ) { -- return this.pushStack( winnow(this, selector, true), "filter", selector ); -- }, -- -- is: function( selector ) { -- return !!selector && ( -- typeof selector === "string" ? -- // If this is a positional selector, check membership in the returned set -- // so $("p:first").is("p:last") won't return true for a doc with two "p". -- POS.test( selector ) ? -- jQuery( selector, this.context ).index( this[0] ) >= 0 : -- jQuery.filter( selector, this ).length > 0 : -- this.filter( selector ).length > 0 ); -- }, -- -- closest: function( selectors, context ) { -- var ret = [], i, l, cur = this[0]; -- -- // Array (deprecated as of jQuery 1.7) -- if ( jQuery.isArray( selectors ) ) { -- var level = 1; -- -- while ( cur && cur.ownerDocument && cur !== context ) { -- for ( i = 0; i < selectors.length; i++ ) { -- -- if ( jQuery( cur ).is( selectors[ i ] ) ) { -- ret.push({ selector: selectors[ i ], elem: cur, level: level }); -- } -- } -- -- cur = cur.parentNode; -- level++; -- } -- -- return ret; -- } -- -- // String -- var pos = POS.test( selectors ) || typeof selectors !== "string" ? -- jQuery( selectors, context || this.context ) : -- 0; -- -- for ( i = 0, l = this.length; i < l; i++ ) { -- cur = this[i]; -- -- while ( cur ) { -- if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { -- ret.push( cur ); -- break; -- -- } else { -- cur = cur.parentNode; -- if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { -- break; -- } -- } -- } -- } -- -- ret = ret.length > 1 ? jQuery.unique( ret ) : ret; -- -- return this.pushStack( ret, "closest", selectors ); -- }, -- -- // Determine the position of an element within -- // the matched set of elements -- index: function( elem ) { -- -- // No argument, return index in parent -- if ( !elem ) { -- return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; -- } -- -- // index in selector -- if ( typeof elem === "string" ) { -- return jQuery.inArray( this[0], jQuery( elem ) ); -- } -- -- // Locate the position of the desired element -- return jQuery.inArray( -- // If it receives a jQuery object, the first element is used -- elem.jquery ? elem[0] : elem, this ); -- }, -- -- add: function( selector, context ) { -- var set = typeof selector === "string" ? -- jQuery( selector, context ) : -- jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), -- all = jQuery.merge( this.get(), set ); -- -- return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? -- all : -- jQuery.unique( all ) ); -- }, -- -- andSelf: function() { -- return this.add( this.prevObject ); -- } --}); -- --// A painfully simple check to see if an element is disconnected --// from a document (should be improved, where feasible). --function isDisconnected( node ) { -- return !node || !node.parentNode || node.parentNode.nodeType === 11; --} -- --jQuery.each({ -- parent: function( elem ) { -- var parent = elem.parentNode; -- return parent && parent.nodeType !== 11 ? parent : null; -- }, -- parents: function( elem ) { -- return jQuery.dir( elem, "parentNode" ); -- }, -- parentsUntil: function( elem, i, until ) { -- return jQuery.dir( elem, "parentNode", until ); -- }, -- next: function( elem ) { -- return jQuery.nth( elem, 2, "nextSibling" ); -- }, -- prev: function( elem ) { -- return jQuery.nth( elem, 2, "previousSibling" ); -- }, -- nextAll: function( elem ) { -- return jQuery.dir( elem, "nextSibling" ); -- }, -- prevAll: function( elem ) { -- return jQuery.dir( elem, "previousSibling" ); -- }, -- nextUntil: function( elem, i, until ) { -- return jQuery.dir( elem, "nextSibling", until ); -- }, -- prevUntil: function( elem, i, until ) { -- return jQuery.dir( elem, "previousSibling", until ); -- }, -- siblings: function( elem ) { -- return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); -- }, -- children: function( elem ) { -- return jQuery.sibling( elem.firstChild ); -- }, -- contents: function( elem ) { -- return jQuery.nodeName( elem, "iframe" ) ? -- elem.contentDocument || elem.contentWindow.document : -- jQuery.makeArray( elem.childNodes ); -- } --}, function( name, fn ) { -- jQuery.fn[ name ] = function( until, selector ) { -- var ret = jQuery.map( this, fn, until ); -- -- if ( !runtil.test( name ) ) { -- selector = until; -- } -- -- if ( selector && typeof selector === "string" ) { -- ret = jQuery.filter( selector, ret ); -- } -- -- ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; -- -- if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { -- ret = ret.reverse(); -- } -- -- return this.pushStack( ret, name, slice.call( arguments ).join(",") ); -- }; --}); -- --jQuery.extend({ -- filter: function( expr, elems, not ) { -- if ( not ) { -- expr = ":not(" + expr + ")"; -- } -- -- return elems.length === 1 ? -- jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : -- jQuery.find.matches(expr, elems); -- }, -- -- dir: function( elem, dir, until ) { -- var matched = [], -- cur = elem[ dir ]; -- -- while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { -- if ( cur.nodeType === 1 ) { -- matched.push( cur ); -- } -- cur = cur[dir]; -- } -- return matched; -- }, -- -- nth: function( cur, result, dir, elem ) { -- result = result || 1; -- var num = 0; -- -- for ( ; cur; cur = cur[dir] ) { -- if ( cur.nodeType === 1 && ++num === result ) { -- break; -- } -- } -- -- return cur; -- }, -- -- sibling: function( n, elem ) { -- var r = []; -- -- for ( ; n; n = n.nextSibling ) { -- if ( n.nodeType === 1 && n !== elem ) { -- r.push( n ); -- } -- } -- -- return r; -- } --}); -- --// Implement the identical functionality for filter and not --function winnow( elements, qualifier, keep ) { -- -- // Can't pass null or undefined to indexOf in Firefox 4 -- // Set to 0 to skip string check -- qualifier = qualifier || 0; -- -- if ( jQuery.isFunction( qualifier ) ) { -- return jQuery.grep(elements, function( elem, i ) { -- var retVal = !!qualifier.call( elem, i, elem ); -- return retVal === keep; -- }); -- -- } else if ( qualifier.nodeType ) { -- return jQuery.grep(elements, function( elem, i ) { -- return ( elem === qualifier ) === keep; -- }); -- -- } else if ( typeof qualifier === "string" ) { -- var filtered = jQuery.grep(elements, function( elem ) { -- return elem.nodeType === 1; -- }); -- -- if ( isSimple.test( qualifier ) ) { -- return jQuery.filter(qualifier, filtered, !keep); -- } else { -- qualifier = jQuery.filter( qualifier, filtered ); -- } -- } -- -- return jQuery.grep(elements, function( elem, i ) { -- return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; -- }); --} -- -- -- -- --function createSafeFragment( document ) { -- var list = nodeNames.split( "|" ), -- safeFrag = document.createDocumentFragment(); -- -- if ( safeFrag.createElement ) { -- while ( list.length ) { -- safeFrag.createElement( -- list.pop() -- ); -- } -- } -- return safeFrag; --} -- --var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + -- "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", -- rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, -- rleadingWhitespace = /^\s+/, -- rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, -- rtagName = /<([\w:]+)/, -- rtbody = /]", "i"), -- // checked="checked" or checked -- rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, -- rscriptType = /\/(java|ecma)script/i, -- rcleanScript = /^\s*", "" ], -- legend: [ 1, "
", "
" ], -- thead: [ 1, "", "
" ], -- tr: [ 2, "", "
" ], -- td: [ 3, "", "
" ], -- col: [ 2, "", "
" ], -- area: [ 1, "", "" ], -- _default: [ 0, "", "" ] -- }, -- safeFragment = createSafeFragment( document ); -- --wrapMap.optgroup = wrapMap.option; --wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; --wrapMap.th = wrapMap.td; -- --// IE can't serialize and -- -- -- -- -- -- -- -- --
--
--
--
-- -- --

Index

-- --
-- --
-- -- --
--
--
--
--
-- -- -- -- -- --
--
--
--
-- -- -- -- -\ No newline at end of file -diff --git a/webhub/_build/html/objects.inv b/webhub/_build/html/objects.inv -deleted file mode 100644 -index 5c344c4..0000000 -Binary files a/webhub/_build/html/objects.inv and /dev/null differ -diff --git a/webhub/_build/html/search.html b/webhub/_build/html/search.html -deleted file mode 100644 -index 5076d44..0000000 ---- a/webhub/_build/html/search.html -+++ /dev/null -@@ -1,99 +0,0 @@ -- -- -- -- -- -- -- -- Search — systerspcweb 2.7.6 documentation -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
--
--
--
-- --

Search

--
-- --

-- Please activate JavaScript to enable the search -- functionality. --

--
--

-- From here you can search these documents. Enter your search -- words into the box below and click "search". Note that the search -- function will automatically search for all of the words. Pages -- containing fewer words won't appear in the result list. --

--
-- -- -- --
-- --
-- --
-- --
--
--
--
--
--
--
--
--
-- -- -- -- -\ No newline at end of file -diff --git a/webhub/_build/html/searchindex.js b/webhub/_build/html/searchindex.js -deleted file mode 100644 -index 387abf3..0000000 ---- a/webhub/_build/html/searchindex.js -+++ /dev/null -@@ -1 +0,0 @@ --Search.setIndex({envversion:42,terms:{content:0,index:0,modul:0,search:0,page:0},objtypes:{},objnames:{},filenames:["systerspcweb"],titles:["Welcome to systerspcweb’s documentation!"],objects:{},titleterms:{systerspcweb:0,document:0,welcom:0,indic:0,tabl:0}}) -\ No newline at end of file -diff --git a/webhub/_build/html/systerspcweb.html b/webhub/_build/html/systerspcweb.html -deleted file mode 100644 -index f41aed1..0000000 ---- a/webhub/_build/html/systerspcweb.html -+++ /dev/null -@@ -1,109 +0,0 @@ -- -- -- -- -- -- -- -- Welcome to systerspcweb’s documentation! — systerspcweb 2.7.6 documentation -- -- -- -- -- -- -- -- -- -- -- -- -- --
--
--
--
-- --
--

Welcome to systerspcweb’s documentation!

--

Contents:

--
--
    --
--
--
--
--

Indices and tables

-- --
-- -- --
--
--
--
--
--

Table Of Contents

-- -- --

This Page

-- -- -- --
--
--
--
-- -- -- -- -\ No newline at end of file -diff --git a/webhub/conf.py b/webhub/conf.py -deleted file mode 100644 -index 4f5a1cd..0000000 ---- a/webhub/conf.py -+++ /dev/null -@@ -1,263 +0,0 @@ --# -*- coding: utf-8 -*- --# --# systerspcweb documentation build configuration file, created by --# sphinx-quickstart on Wed Aug 13 20:07:49 2014. --# --# This file is execfile()d with the current directory set to its --# containing dir. --# --# Note that not all possible configuration values are present in this --# autogenerated file. --# --# All configuration values have a default; values that are commented out --# serve to show the default. -- --import sys --import os -- --sys.path.append('/home/rani/vdapp/webhub') -- -- --# If extensions (or modules to document with autodoc) are in another directory, --# add these directories to sys.path here. If the directory is relative to the --# documentation root, use os.path.abspath to make it absolute, like shown here. --#sys.path.insert(0, os.path.abspath('.')) -- --# -- General configuration ------------------------------------------------ -- --# If your documentation needs a minimal Sphinx version, state it here. --#needs_sphinx = '1.0' -- --# Add any Sphinx extension module names here, as strings. They can be --# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom --# ones. --extensions = [ -- 'sphinx.ext.autodoc', --] -- --# Add any paths that contain templates here, relative to this directory. --templates_path = ['_templates'] -- --# The suffix of source filenames. --source_suffix = '.txt' -- --# The encoding of source files. --#source_encoding = 'utf-8-sig' -- --# The master toctree document. --master_doc = 'systerspcweb' -- --# General information about the project. --project = u'systerspcweb' --copyright = u'2014, vaibhavi, rani' -- --# The version info for the project you're documenting, acts as replacement for --# |version| and |release|, also used in various other places throughout the --# built documents. --# --# The short X.Y version. --version = '2.7' --# The full version, including alpha/beta/rc tags. --release = '2.7.6' -- --# The language for content autogenerated by Sphinx. Refer to documentation --# for a list of supported languages. --#language = None -- --# There are two options for replacing |today|: either, you set today to some --# non-false value, then it is used: --#today = '' --# Else, today_fmt is used as the format for a strftime call. --#today_fmt = '%B %d, %Y' -- --# List of patterns, relative to source directory, that match files and --# directories to ignore when looking for source files. --exclude_patterns = ['_build'] -- --# The reST default role (used for this markup: `text`) to use for all --# documents. --#default_role = None -- --# If true, '()' will be appended to :func: etc. cross-reference text. --#add_function_parentheses = True -- --# If true, the current module name will be prepended to all description --# unit titles (such as .. function::). --#add_module_names = True -- --# If true, sectionauthor and moduleauthor directives will be shown in the --# output. They are ignored by default. --#show_authors = False -- --# The name of the Pygments (syntax highlighting) style to use. --pygments_style = 'sphinx' -- --# A list of ignored prefixes for module index sorting. --#modindex_common_prefix = [] -- --# If true, keep warnings as "system message" paragraphs in the built documents. --#keep_warnings = False -- -- --# -- Options for HTML output ---------------------------------------------- -- --# The theme to use for HTML and HTML Help pages. See the documentation for --# a list of builtin themes. --html_theme = 'default' -- --# Theme options are theme-specific and customize the look and feel of a theme --# further. For a list of options available for each theme, see the --# documentation. --#html_theme_options = {} -- --# Add any paths that contain custom themes here, relative to this directory. --#html_theme_path = [] -- --# The name for this set of Sphinx documents. If None, it defaults to --# " v documentation". --#html_title = None -- --# A shorter title for the navigation bar. Default is the same as html_title. --#html_short_title = None -- --# The name of an image file (relative to this directory) to place at the top --# of the sidebar. --#html_logo = None -- --# The name of an image file (within the static path) to use as favicon of the --# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 --# pixels large. --#html_favicon = None -- --# Add any paths that contain custom static files (such as style sheets) here, --# relative to this directory. They are copied after the builtin static files, --# so a file named "default.css" will overwrite the builtin "default.css". --html_static_path = ['_static'] -- --# Add any extra paths that contain custom files (such as robots.txt or --# .htaccess) here, relative to this directory. These files are copied --# directly to the root of the documentation. --#html_extra_path = [] -- --# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, --# using the given strftime format. --#html_last_updated_fmt = '%b %d, %Y' -- --# If true, SmartyPants will be used to convert quotes and dashes to --# typographically correct entities. --#html_use_smartypants = True -- --# Custom sidebar templates, maps document names to template names. --#html_sidebars = {} -- --# Additional templates that should be rendered to pages, maps page names to --# template names. --#html_additional_pages = {} -- --# If false, no module index is generated. --#html_domain_indices = True -- --# If false, no index is generated. --#html_use_index = True -- --# If true, the index is split into individual pages for each letter. --#html_split_index = False -- --# If true, links to the reST sources are added to the pages. --#html_show_sourcelink = True -- --# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. --#html_show_sphinx = True -- --# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. --#html_show_copyright = True -- --# If true, an OpenSearch description file will be output, and all pages will --# contain a tag referring to it. The value of this option must be the --# base URL from which the finished HTML is served. --#html_use_opensearch = '' -- --# This is the file name suffix for HTML files (e.g. ".xhtml"). --#html_file_suffix = None -- --# Output file base name for HTML help builder. --htmlhelp_basename = 'systerspcwebdoc' -- -- --# -- Options for LaTeX output --------------------------------------------- -- --latex_elements = { --# The paper size ('letterpaper' or 'a4paper'). --#'papersize': 'letterpaper', -- --# The font size ('10pt', '11pt' or '12pt'). --#'pointsize': '10pt', -- --# Additional stuff for the LaTeX preamble. --#'preamble': '', --} -- --# Grouping the document tree into LaTeX files. List of tuples --# (source start file, target name, title, --# author, documentclass [howto, manual, or own class]). --latex_documents = [ -- ('systerspcweb', 'systerspcweb.tex', u'systerspcweb Documentation', -- u'vaibhavi, rani', 'manual'), --] -- --# The name of an image file (relative to this directory) to place at the top of --# the title page. --#latex_logo = None -- --# For "manual" documents, if this is true, then toplevel headings are parts, --# not chapters. --#latex_use_parts = False -- --# If true, show page references after internal links. --#latex_show_pagerefs = False -- --# If true, show URL addresses after external links. --#latex_show_urls = False -- --# Documents to append as an appendix to all manuals. --#latex_appendices = [] -- --# If false, no module index is generated. --#latex_domain_indices = True -- -- --# -- Options for manual page output --------------------------------------- -- --# One entry per manual page. List of tuples --# (source start file, name, description, authors, manual section). --man_pages = [ -- ('systerspcweb', 'systerspcweb', u'systerspcweb Documentation', -- [u'vaibhavi, rani'], 1) --] -- --# If true, show URL addresses after external links. --#man_show_urls = False -- -- --# -- Options for Texinfo output ------------------------------------------- -- --# Grouping the document tree into Texinfo files. List of tuples --# (source start file, target name, title, author, --# dir menu entry, description, category) --texinfo_documents = [ -- ('systerspcweb', 'systerspcweb', u'systerspcweb Documentation', -- u'vaibhavi, rani', 'systerspcweb', 'One line description of project.', -- 'Miscellaneous'), --] -- --# Documents to append as an appendix to all manuals. --#texinfo_appendices = [] -- --# If false, no module index is generated. --#texinfo_domain_indices = True -- --# How to display URL addresses: 'footnote', 'no', or 'inline'. --#texinfo_show_urls = 'footnote' -- --# If true, do not generate a @detailmenu in the "Top" node's menu. --#texinfo_no_detailmenu = False -diff --git a/webhub/make.bat b/webhub/make.bat -deleted file mode 100644 -index db50cfe..0000000 ---- a/webhub/make.bat -+++ /dev/null -@@ -1,242 +0,0 @@ --@ECHO OFF -- --REM Command file for Sphinx documentation -- --if "%SPHINXBUILD%" == "" ( -- set SPHINXBUILD=sphinx-build --) --set BUILDDIR=_build --set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . --set I18NSPHINXOPTS=%SPHINXOPTS% . --if NOT "%PAPER%" == "" ( -- set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% -- set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% --) -- --if "%1" == "" goto help -- --if "%1" == "help" ( -- :help -- echo.Please use `make ^` where ^ is one of -- echo. html to make standalone HTML files -- echo. dirhtml to make HTML files named index.html in directories -- echo. singlehtml to make a single large HTML file -- echo. pickle to make pickle files -- echo. json to make JSON files -- echo. htmlhelp to make HTML files and a HTML help project -- echo. qthelp to make HTML files and a qthelp project -- echo. devhelp to make HTML files and a Devhelp project -- echo. epub to make an epub -- echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter -- echo. text to make text files -- echo. man to make manual pages -- echo. texinfo to make Texinfo files -- echo. gettext to make PO message catalogs -- echo. changes to make an overview over all changed/added/deprecated items -- echo. xml to make Docutils-native XML files -- echo. pseudoxml to make pseudoxml-XML files for display purposes -- echo. linkcheck to check all external links for integrity -- echo. doctest to run all doctests embedded in the documentation if enabled -- goto end --) -- --if "%1" == "clean" ( -- for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i -- del /q /s %BUILDDIR%\* -- goto end --) -- -- --%SPHINXBUILD% 2> nul --if errorlevel 9009 ( -- echo. -- echo.The 'sphinx-build' command was not found. Make sure you have Sphinx -- echo.installed, then set the SPHINXBUILD environment variable to point -- echo.to the full path of the 'sphinx-build' executable. Alternatively you -- echo.may add the Sphinx directory to PATH. -- echo. -- echo.If you don't have Sphinx installed, grab it from -- echo.http://sphinx-doc.org/ -- exit /b 1 --) -- --if "%1" == "html" ( -- %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html -- if errorlevel 1 exit /b 1 -- echo. -- echo.Build finished. The HTML pages are in %BUILDDIR%/html. -- goto end --) -- --if "%1" == "dirhtml" ( -- %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml -- if errorlevel 1 exit /b 1 -- echo. -- echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. -- goto end --) -- --if "%1" == "singlehtml" ( -- %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml -- if errorlevel 1 exit /b 1 -- echo. -- echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. -- goto end --) -- --if "%1" == "pickle" ( -- %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle -- if errorlevel 1 exit /b 1 -- echo. -- echo.Build finished; now you can process the pickle files. -- goto end --) -- --if "%1" == "json" ( -- %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json -- if errorlevel 1 exit /b 1 -- echo. -- echo.Build finished; now you can process the JSON files. -- goto end --) -- --if "%1" == "htmlhelp" ( -- %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp -- if errorlevel 1 exit /b 1 -- echo. -- echo.Build finished; now you can run HTML Help Workshop with the ^ --.hhp project file in %BUILDDIR%/htmlhelp. -- goto end --) -- --if "%1" == "qthelp" ( -- %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp -- if errorlevel 1 exit /b 1 -- echo. -- echo.Build finished; now you can run "qcollectiongenerator" with the ^ --.qhcp project file in %BUILDDIR%/qthelp, like this: -- echo.^> qcollectiongenerator %BUILDDIR%\qthelp\systerspcweb.qhcp -- echo.To view the help file: -- echo.^> assistant -collectionFile %BUILDDIR%\qthelp\systerspcweb.ghc -- goto end --) -- --if "%1" == "devhelp" ( -- %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp -- if errorlevel 1 exit /b 1 -- echo. -- echo.Build finished. -- goto end --) -- --if "%1" == "epub" ( -- %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub -- if errorlevel 1 exit /b 1 -- echo. -- echo.Build finished. The epub file is in %BUILDDIR%/epub. -- goto end --) -- --if "%1" == "latex" ( -- %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex -- if errorlevel 1 exit /b 1 -- echo. -- echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. -- goto end --) -- --if "%1" == "latexpdf" ( -- %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex -- cd %BUILDDIR%/latex -- make all-pdf -- cd %BUILDDIR%/.. -- echo. -- echo.Build finished; the PDF files are in %BUILDDIR%/latex. -- goto end --) -- --if "%1" == "latexpdfja" ( -- %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex -- cd %BUILDDIR%/latex -- make all-pdf-ja -- cd %BUILDDIR%/.. -- echo. -- echo.Build finished; the PDF files are in %BUILDDIR%/latex. -- goto end --) -- --if "%1" == "text" ( -- %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text -- if errorlevel 1 exit /b 1 -- echo. -- echo.Build finished. The text files are in %BUILDDIR%/text. -- goto end --) -- --if "%1" == "man" ( -- %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man -- if errorlevel 1 exit /b 1 -- echo. -- echo.Build finished. The manual pages are in %BUILDDIR%/man. -- goto end --) -- --if "%1" == "texinfo" ( -- %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo -- if errorlevel 1 exit /b 1 -- echo. -- echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. -- goto end --) -- --if "%1" == "gettext" ( -- %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale -- if errorlevel 1 exit /b 1 -- echo. -- echo.Build finished. The message catalogs are in %BUILDDIR%/locale. -- goto end --) -- --if "%1" == "changes" ( -- %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes -- if errorlevel 1 exit /b 1 -- echo. -- echo.The overview file is in %BUILDDIR%/changes. -- goto end --) -- --if "%1" == "linkcheck" ( -- %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck -- if errorlevel 1 exit /b 1 -- echo. -- echo.Link check complete; look for any errors in the above output ^ --or in %BUILDDIR%/linkcheck/output.txt. -- goto end --) -- --if "%1" == "doctest" ( -- %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest -- if errorlevel 1 exit /b 1 -- echo. -- echo.Testing of doctests in the sources finished, look at the ^ --results in %BUILDDIR%/doctest/output.txt. -- goto end --) -- --if "%1" == "xml" ( -- %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml -- if errorlevel 1 exit /b 1 -- echo. -- echo.Build finished. The XML files are in %BUILDDIR%/xml. -- goto end --) -- --if "%1" == "pseudoxml" ( -- %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml -- if errorlevel 1 exit /b 1 -- echo. -- echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. -- goto end --) -- --:end -diff --git a/webhub/systerspcweb.txt b/webhub/systerspcweb.txt -deleted file mode 100644 -index 01325ed..0000000 ---- a/webhub/systerspcweb.txt -+++ /dev/null -@@ -1,26 +0,0 @@ --.. systerspcweb documentation master file, created by -- sphinx-quickstart on Wed Aug 13 20:07:49 2014. -- You can adapt this file completely to your liking, but it should at least -- contain the root `toctree` directive. -- --Welcome to systerspcweb's documentation! --======================================== -- --Contents: -- --.. toctree:: -- :maxdepth: 2 -- --.. automodule:: serializers.py -- --.. autoclass:: UserSerializer -- :members: -- -- --Indices and tables --================== -- --* :ref:`genindex` --* :ref:`modindex` --* :ref:`search` -- - -commit b08153198d9c0ff9c0d528dec3ed2dc9e00d5934 -Author: desaivaibhavi -Date: Sun Aug 17 01:55:07 2014 +0530 - - documentation added - -diff --git a/docs/API Documentation.pdf b/docs/API Documentation.pdf -new file mode 100644 -index 0000000..6aad3e1 -Binary files /dev/null and b/docs/API Documentation.pdf differ -diff --git a/docs/APIDocumentation.pdf b/docs/APIDocumentation.pdf -deleted file mode 100644 -index 6aad3e1..0000000 -Binary files a/docs/APIDocumentation.pdf and /dev/null differ -diff --git a/docs/Installation Guidelines b/docs/Installation Guidelines -new file mode 100644 -index 0000000..4e28fe7 ---- /dev/null -+++ b/docs/Installation Guidelines -@@ -0,0 +1,37 @@ -+Readme file : -+ -+Details about the folders -+ -+infohub : contains the python environment setup, it contains 4 files - init.py, settings.py, urls.py and wsgi.py -+settings.py has the main configuration settings like dependencies, database, timezone etc. -+ -+ui : contains the ui page templates of the site, it conains the html,css, js page templates with applied jinja integration. Also, I have used bootstrap for responsiveness and better UI design. -+ -+webhub : contains the python-django backend of the site, it conains 7 files - init.py, admin.py, checker.py, models.py, tests.py, urls.py and views.py -+admin.py contains the models that are to be added in the admin panel -+checker.py has a check function that redirects the user to the home page depending upon his current status (i.e. login/logout) -+models.py has all the information about the models we are going to have in the database -+urls.py has the urls of the pages created connected with the respective views -+views.py has all the views, ie function to call different views and render the respective values from the backend -+ -+manage.py : is the file that is used to run the application -+ -+ -+Guidelines to run the application : -+ -+I had to reinstall postgres and python on the VM provided. Also, I had to install python-psycopg2 and jinja on the VM. Make sure the internet is working as I have used some online resources right now. -+ -+To run the application, -+1. Start the VM. Install the mentioned dependencies if required -+2. Go to the directory which has manage.py file -+3. Syncing with the database : run the following command from the terminal -+ python manage.py syncdb -+4. You might be asked to create a super user. Create one. -+5. Runnning the server : run the following command from the terminal -+ python manage.py runserver 0.0.0.0:8000 -+6. Open the web-browser and go to http://192.168.33.10:8000/admin. Log in (with the superuser credentials). -+7. You will have to create one user from the admin panel.Create one user and add it to the new pcuser. Log out. -+8. Now go to http://192.168.33.10:8000/. Login with the credential of the pcuser that you created from the admin panel. -+9. Done ! -+ -+ -diff --git a/docs/Readme.pdf b/docs/Readme.pdf -new file mode 100644 -index 0000000..0e7b2ae -Binary files /dev/null and b/docs/Readme.pdf differ -diff --git a/docs/Software Design Document.pdf b/docs/Software Design Document.pdf -new file mode 100644 -index 0000000..f3a1f4a -Binary files /dev/null and b/docs/Software Design Document.pdf differ -diff --git a/docs/Workflow and Progress Document.pdf b/docs/Workflow and Progress Document.pdf -new file mode 100644 -index 0000000..eb6280a -Binary files /dev/null and b/docs/Workflow and Progress Document.pdf differ -diff --git a/docs/WorkflowandProgress.pdf b/docs/WorkflowandProgress.pdf -deleted file mode 100644 -index eb6280a..0000000 -Binary files a/docs/WorkflowandProgress.pdf and /dev/null differ -diff --git a/readmeForCode b/readmeForCode -deleted file mode 100644 -index 4e28fe7..0000000 ---- a/readmeForCode -+++ /dev/null -@@ -1,37 +0,0 @@ --Readme file : -- --Details about the folders -- --infohub : contains the python environment setup, it contains 4 files - init.py, settings.py, urls.py and wsgi.py --settings.py has the main configuration settings like dependencies, database, timezone etc. -- --ui : contains the ui page templates of the site, it conains the html,css, js page templates with applied jinja integration. Also, I have used bootstrap for responsiveness and better UI design. -- --webhub : contains the python-django backend of the site, it conains 7 files - init.py, admin.py, checker.py, models.py, tests.py, urls.py and views.py --admin.py contains the models that are to be added in the admin panel --checker.py has a check function that redirects the user to the home page depending upon his current status (i.e. login/logout) --models.py has all the information about the models we are going to have in the database --urls.py has the urls of the pages created connected with the respective views --views.py has all the views, ie function to call different views and render the respective values from the backend -- --manage.py : is the file that is used to run the application -- -- --Guidelines to run the application : -- --I had to reinstall postgres and python on the VM provided. Also, I had to install python-psycopg2 and jinja on the VM. Make sure the internet is working as I have used some online resources right now. -- --To run the application, --1. Start the VM. Install the mentioned dependencies if required --2. Go to the directory which has manage.py file --3. Syncing with the database : run the following command from the terminal -- python manage.py syncdb --4. You might be asked to create a super user. Create one. --5. Runnning the server : run the following command from the terminal -- python manage.py runserver 0.0.0.0:8000 --6. Open the web-browser and go to http://192.168.33.10:8000/admin. Log in (with the superuser credentials). --7. You will have to create one user from the admin panel.Create one user and add it to the new pcuser. Log out. --8. Now go to http://192.168.33.10:8000/. Login with the credential of the pcuser that you created from the admin panel. --9. Done ! -- -- - -commit 713d50d259390b782927bc186ba7c098b0af23c0 -Author: desaivaibhavi -Date: Sat Aug 16 13:36:40 2014 +0530 - - documents added : workflow and progress doc, api doc - -diff --git a/docs/APIDocumentation.pdf b/docs/APIDocumentation.pdf -new file mode 100644 -index 0000000..6aad3e1 -Binary files /dev/null and b/docs/APIDocumentation.pdf differ -diff --git a/docs/DocumentationusingAPIs.pdf b/docs/DocumentationusingAPIs.pdf -deleted file mode 100644 -index 43a7f43..0000000 -Binary files a/docs/DocumentationusingAPIs.pdf and /dev/null differ -diff --git a/docs/SoftwareDesignDocument.pdf b/docs/SoftwareDesignDocument.pdf -deleted file mode 100644 -index 1f026b8..0000000 -Binary files a/docs/SoftwareDesignDocument.pdf and /dev/null differ -diff --git a/docs/WorkflowandProgress.pdf b/docs/WorkflowandProgress.pdf -new file mode 100644 -index 0000000..eb6280a -Binary files /dev/null and b/docs/WorkflowandProgress.pdf differ - -commit 00079d6991213fbd20e5be8b4335f51a0abff9d7 -Author: desaivaibhavi -Date: Sat Aug 16 13:16:49 2014 +0530 - - volunteer removed from summary - -diff --git a/ui/summary.html b/ui/summary.html -index dbe988f..b73d450 100644 ---- a/ui/summary.html -+++ b/ui/summary.html -@@ -77,36 +77,6 @@ email : ranihaileydesai@gmail.com - {% endif %} - -
-- Details by Volunteer

-- {%if all_vol|length ==0 %} --

There are No Volunteers right now.











-- {% else %} -- -- {% for vol in all_vol %} -- -- Name of volunteer : {{vol.vol_name}}
-- Sector : {{vol.vol_sector}}
-- Post : {{vol.vol_ptpost}}
-- Activity : -- {% for item in vol.vol_activity.all() %} -- {{ item }} -- {% endfor %} --
-- Measurement : -- {% for item in vol.vol_meas.all() %} -- {{ item }} -- {% endfor %} --
-- Cohort : -- {% for item in vol.vol_cohort.all() %} -- {{ item }} -- {% endfor %} --
--
--
-- {% endfor %} -- -- {% endif %} -
- - - -commit 6044033ec6e5b565144f2848e5edc92239f88b8a -Author: desaivaibhavi -Date: Fri Aug 15 18:46:05 2014 +0530 - - change profile pic removed - -diff --git a/ui/edit_profile.html b/ui/edit_profile.html -index 0fd7171..a47fc45 100644 ---- a/ui/edit_profile.html -+++ b/ui/edit_profile.html -@@ -56,12 +56,7 @@ email : ranihaileydesai@gmail.com - - - --
-- Change Profile Photo: --
-- --
-- -+ - -
-
- -commit 1e1b10ba4501eeb2b8857139e60842d1bbcae5a9 -Author: desaivaibhavi -Date: Fri Aug 15 18:24:18 2014 +0530 - - changes with app - -diff --git a/ui/newpost.html b/ui/newpost.html -index 6f1f549..8b43195 100644 ---- a/ui/newpost.html -+++ b/ui/newpost.html -@@ -15,7 +15,7 @@ email : ranihaileydesai@gmail.com -





-

Malaria : infoHub

- --
-+
-
-

New Post

-
-diff --git a/ui/signup.html b/ui/signup.html -index 53327ef..96f0c79 100644 ---- a/ui/signup.html -+++ b/ui/signup.html -@@ -18,7 +18,7 @@ email : ranihaileydesai@gmail.com - -
- --
-+
-
-
-

Sign Up Form

-diff --git a/webhub/views.py b/webhub/views.py -index 4c6e047..f952bb6 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -1037,7 +1037,7 @@ def post_new(request): - owner = request.user.pcuser - title_post = request.REQUEST['title'] - description_post = request.REQUEST['description'] -- link_post = request.REQUEST['link'] -+ - - entry = Post(owner=owner, - title_post=title_post, - -commit e1f966af1e7ff166d7283e2a10714ac7590e483e -Author: desaivaibhavi -Date: Fri Aug 15 18:19:59 2014 +0530 - - changes with app - -diff --git a/webhub/views.py b/webhub/views.py -index c5c30ad..4c6e047 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -1086,109 +1086,61 @@ def edit_post(request): - - if postobj.title_post <> title_post: - if postobj.description_post <> description_post: -- if postobj.link_post <> link_post: -- entry = RevPost(owner_rev=owner, -- owner_rev_post=postobj, -- title_post_rev=postobj.title_post, -- description_post_rev=postobj.description_post, -- link_post_rev=postobj.link_post, -- title_change=True, -- description_change=True, -- link_change=True, -- ) -- entry.save() -- else: -+ - entry = RevPost(owner_rev=owner, - owner_rev_post=postobj, - title_post_rev=postobj.title_post, - description_post_rev=postobj.description_post, -- link_post_rev=postobj.link_post, -+ - title_change=True, - description_change=True, -- link_change=False, -+ - ) - entry.save() -+ - else: -- if postobj.link_post <> link_post: -- entry = RevPost(owner_rev=owner, -- owner_rev_post=postobj, -- title_post_rev=postobj.title_post, -- description_post_rev=postobj.description_post, -- link_post_rev=postobj.link_post, -- title_change=True, -- description_change=False, -- link_change=True, -- ) -- entry.save() -- else: -+ - entry = RevPost(owner_rev=owner, - owner_rev_post=postobj, - title_post_rev=postobj.title_post, - description_post_rev=postobj.description_post, -- link_post_rev=postobj.link_post, -+ - title_change=True, - description_change=False, -- link_change=False, -+ - ) - entry.save() -- -- -+ - else: - if postobj.description_post <> description_post: -- if postobj.link_post <> link_post: -- entry = RevPost(owner_rev=owner, -- owner_rev_post=postobj, -- title_post_rev=postobj.title_post, -- description_post_rev=postobj.description_post, -- link_post_rev=postobj.link_post, -- title_change=False, -- description_change=True, -- link_change=True, -- ) -- entry.save() -- else: -+ - entry = RevPost(owner_rev=owner, - owner_rev_post=postobj, - title_post_rev=postobj.title_post, - description_post_rev=postobj.description_post, -- link_post_rev=postobj.link_post, -+ - title_change=False, - description_change=True, -- link_change=False, -+ - ) - entry.save() -- -- -+ - else: -- if postobj.link_post <> link_post: -- entry = RevPost(owner_rev=owner, -- owner_rev_post=postobj, -- title_post_rev=postobj.title_post, -- description_post_rev=postobj.description_post, -- link_post_rev=postobj.link_post, -- title_change=False, -- description_change=False, -- link_change=True, -- ) -- entry.save() -- else: -+ - entry = RevPost(owner_rev=owner, - owner_rev_post=postobj, - title_post_rev=postobj.title_post, - description_post_rev=postobj.description_post, -- link_post_rev=postobj.link_post, -+ - title_change=False, - description_change=False, -- link_change=False, -+ - ) - entry.save() -- -- -- -- -+ - postobj.title_post = title_post - postobj.description_post = description_post -- postobj.link_post = link_post -+ - - postobj.save() - - -commit fa252af085aed90a9f4d6bb68156840338b4a72b -Author: desaivaibhavi -Date: Fri Aug 15 18:14:15 2014 +0530 - - reseting database - -diff --git a/ui/signup.html b/ui/signup.html -index 9155bc4..53327ef 100644 ---- a/ui/signup.html -+++ b/ui/signup.html -@@ -52,12 +52,12 @@ email : ranihaileydesai@gmail.com -

Set Password :

- -

Confirm Password :

-- -+
both passwords should match
- -

Phone :

- -

Location :

-- -+
should be text
- - - -diff --git a/webhub/models.py b/webhub/models.py -index 637b905..1585f24 100644 ---- a/webhub/models.py -+++ b/webhub/models.py -@@ -19,11 +19,7 @@ def update_filename(instance, filename): - format = instance.user.username + ".jpg" - return os.path.join(path, format) - --#To update the filename of the newly uploaded photo of the post --def update_filename1(instance, filename): -- path = '/vagrant/submit/media/propics/' -- format = instance.owner.user.username + "post.jpg" -- return os.path.join(path, format) -+ - - #Django provides a table called user that stores basic user information like username, password and email id. - -diff --git a/webhub/views.py b/webhub/views.py -index 24b607d..c5c30ad 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -1038,16 +1038,11 @@ def post_new(request): - title_post = request.REQUEST['title'] - description_post = request.REQUEST['description'] - link_post = request.REQUEST['link'] -- imageobj_post = request.FILES['image_post'] -- image_post = '/static/' + owner.user.username + "post.jpg" -- -- -+ - entry = Post(owner=owner, - title_post=title_post, - description_post=description_post, -- link_post=link_post, -- imageobj_post=imageobj_post, -- image_post=image_post, -+ - ) - entry.save() - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, -@@ -1085,28 +1080,9 @@ def edit_post(request): - - title_post = request.REQUEST['title'] - description_post = request.REQUEST['description'] -- link_post = request.REQUEST['link'] -- - -- #To remove post picture -- if 'reset_image' in request.REQUEST.keys(): -- postobj.image_post = "http://allfacebook.com/files/2012/03/bluepin.png" -- if str(postobj.imageobj_post) <> '': -- path = '/vagrant/submit/media/propics/' + owner.user.username + "post.jpg" -- if os.path.isfile(path): -- os.remove(path) -- postobj.save() -- return edit_post(request) - - -- if 'image' in request.FILES.keys(): -- #delete old file -- if str(postobj.imageobj_post) <> '': -- path = '/vagrant/submit/media/propics/' + owner.user.username + "post.jpg" -- if os.path.isfile(path): -- os.remove(path) -- postobj.imageobj_post = request.FILES['image'] -- postobj.image_post = '/static/' + owner.user.username + "post.jpg" - - if postobj.title_post <> title_post: - if postobj.description_post <> description_post: - -commit fe846cd1cc033badff0b515d1781c006944e1f05 -Author: desaivaibhavi -Date: Fri Aug 15 18:08:08 2014 +0530 - - removing the image and link from serializers - -diff --git a/webhub/serializers.py b/webhub/serializers.py -index 3078879..b594bfa 100644 ---- a/webhub/serializers.py -+++ b/webhub/serializers.py -@@ -17,13 +17,13 @@ class PcuserSerializer(serializers.ModelSerializer): - class PostSerializer(serializers.ModelSerializer): - class Meta: - model = Post -- fields = ('owner', 'title_post', 'description_post', 'link_post', 'created','updated','id','image_post','imageobj_post','id') -+ fields = ('owner', 'title_post', 'description_post', 'created','updated','id') - - - class RevPostSerializer(serializers.ModelSerializer): - class Meta: - model = RevPost -- fields = ('owner_rev_post', 'owner_rev', 'title_post_rev', 'description_post_rev', 'link_post_rev', 'created','id','title_change','description_change','link_change','id') -+ fields = ('owner_rev_post', 'owner_rev', 'title_post_rev', 'description_post_rev', 'created','id','title_change','description_change','id') - - #Peacetrack begins here - - -commit ebb18c1c85e19f1c8c2a3600cd4a9b3de9aad590 -Author: desaivaibhavi -Date: Fri Aug 15 18:03:55 2014 +0530 - - removing the image and link - -diff --git a/ui/editpost.html b/ui/editpost.html -index aa4e68c..8ffb137 100644 ---- a/ui/editpost.html -+++ b/ui/editpost.html -@@ -46,37 +46,6 @@ email : ranihaileydesai@gmail.com -
-
- --
--
--
--
--
--

Link

--
--
-- -- --
--
-- -- --
--
--
--
--

Change image

--
--
-- --
--
-- -- --
--
-- --
--
- -
- -diff --git a/ui/newpost.html b/ui/newpost.html -index a43b5f4..6f1f549 100644 ---- a/ui/newpost.html -+++ b/ui/newpost.html -@@ -43,28 +43,7 @@ email : ranihaileydesai@gmail.com -
-
-
--
--
--
--
--

Link

--
--
-- --
--
- --
--
--
--
--
--

Add image

--
--
-- --
--
-
- -
-diff --git a/ui/peacetrack.html b/ui/peacetrack.html -index dd15436..fc37ee7 100644 ---- a/ui/peacetrack.html -+++ b/ui/peacetrack.html -@@ -19,7 +19,7 @@ email : ranihaileydesai@gmail.com -

Graph

-
- --













-+














- {% include "footer.html" %} - - -diff --git a/ui/viewpost.html b/ui/viewpost.html -index 40e2455..7a105b6 100644 ---- a/ui/viewpost.html -+++ b/ui/viewpost.html -@@ -44,22 +44,7 @@ email : ranihaileydesai@gmail.com -
-
- -- {% if post.link_post %} --
--
--
--
--

Link :

--
-- --

-- {% endif %} -- --
-- --
-+ - -
-
-@@ -92,9 +77,7 @@ email : ranihaileydesai@gmail.com - {% if rev.description_change %} - The description has been changed from "{{rev.description_post_rev}}" to "{{post.description_post}}" - {% endif %} -- {% if rev.link_change %} -- The link has been changed from "{{rev.link_post_rev}}" to "{{post.link_post}}" -- {% endif %} -+ - - - -diff --git a/webhub/.~lock.Updated Project Framework Indicator List PeaceTrack.xlsx# b/webhub/.~lock.Updated Project Framework Indicator List PeaceTrack.xlsx# -deleted file mode 100644 -index 9a8992e..0000000 ---- a/webhub/.~lock.Updated Project Framework Indicator List PeaceTrack.xlsx# -+++ /dev/null -@@ -1 +0,0 @@ --,rani,rani-Inspiron-N4050,15.08.2014 13:55,file:///home/rani/.config/libreoffice/4; -\ No newline at end of file -diff --git a/webhub/models.py b/webhub/models.py -index 9143ea1..637b905 100644 ---- a/webhub/models.py -+++ b/webhub/models.py -@@ -71,11 +71,7 @@ class Post(models.Model): - #field to note the timestamp when the post was last updated - updated = models.DateTimeField(auto_now=True) - -- #path to default post image -- image_post = models.CharField(max_length=300, default="http://allfacebook.com/files/2012/03/bluepin.png") -- #image of the post -- imageobj_post = models.ImageField(upload_to=update_filename1) -- -+ - def __unicode__(self): - return self.owner.user.username - -@@ -90,8 +86,7 @@ class RevPost(models.Model): - title_post_rev = models.CharField(max_length=300) - #revised description - description_post_rev = models.CharField(max_length=2000) -- #revised link to important documents -- link_post_rev = models.CharField(max_length=2000) -+ - - - #field to note the timestamp when the revised version was created -@@ -100,8 +95,7 @@ class RevPost(models.Model): - title_change = models.BooleanField(default=False) - #change in description - description_change = models.BooleanField(default=False) -- #change in link to important documents -- link_change = models.BooleanField(default=False) -+ - - - - -commit ae9f11872cdef7f33dcb40c7ca7e47baf4945910 -Author: desaivaibhavi -Date: Fri Aug 15 17:53:03 2014 +0530 - - setting footer - -diff --git a/ui/peacetrack.html b/ui/peacetrack.html -index 2598a48..dd15436 100644 ---- a/ui/peacetrack.html -+++ b/ui/peacetrack.html -@@ -19,7 +19,7 @@ email : ranihaileydesai@gmail.com -

Graph

-
- --















-+













- {% include "footer.html" %} - - - -commit e923666e0096a59a33c6195cb93995971c0f0cb1 -Author: desaivaibhavi -Date: Fri Aug 15 17:51:31 2014 +0530 - - many to many relationship done in summary - -diff --git a/ui/peacetrack.html b/ui/peacetrack.html -index 4ffdabc..2598a48 100644 ---- a/ui/peacetrack.html -+++ b/ui/peacetrack.html -@@ -14,12 +14,13 @@ email : ranihaileydesai@gmail.com - {% include "header.html" %} -





-
--

Summary

-+

Summary

-

Volunteer

--

Graph

-+

Graph

-
- --













-+















-+ {% include "footer.html" %} - - - -diff --git a/ui/summary.html b/ui/summary.html -index 3afa2c9..dbe988f 100644 ---- a/ui/summary.html -+++ b/ui/summary.html -@@ -20,7 +20,7 @@ email : ranihaileydesai@gmail.com -

- - -- Details by Post

-+ Details by Post

- - {%if all_post|length ==0 %} -

There are No Posts right now.











-@@ -39,7 +39,7 @@ email : ranihaileydesai@gmail.com - - {% endif %} -
-- Details by Sector

-+ Details by Sector

- - {%if all_sector|length ==0 %} -

There are No Sectors right now.











-@@ -58,7 +58,7 @@ email : ranihaileydesai@gmail.com - {% endif %} - -
-- Details by Project

-+ Details by Project

- - {%if all_project|length ==0 %} -

There are No Projects right now.











-@@ -77,7 +77,7 @@ email : ranihaileydesai@gmail.com - {% endif %} - -
-- Details by Volunteer

-+ Details by Volunteer

- {%if all_vol|length ==0 %} -

There are No Volunteers right now.











- {% else %} -@@ -87,9 +87,22 @@ email : ranihaileydesai@gmail.com - Name of volunteer : {{vol.vol_name}}
- Sector : {{vol.vol_sector}}
- Post : {{vol.vol_ptpost}}
-- Activity : {{vol.vol_activity}}
-- Measurement : {{vol.vol_meas}}
-- Cohurt : {{vol.vol_cohort}}
-+ Activity : -+ {% for item in vol.vol_activity.all() %} -+ {{ item }} -+ {% endfor %} -+
-+ Measurement : -+ {% for item in vol.vol_meas.all() %} -+ {{ item }} -+ {% endfor %} -+
-+ Cohort : -+ {% for item in vol.vol_cohort.all() %} -+ {{ item }} -+ {% endfor %} -+
-+ -
- {% endfor %} - - -commit b34624b5a7362759f38f402254e932c7ae71471d -Author: desaivaibhavi -Date: Fri Aug 15 17:47:00 2014 +0530 - - setting footer - -diff --git a/ui/peacetrack.html b/ui/peacetrack.html -index 06d946c..4ffdabc 100644 ---- a/ui/peacetrack.html -+++ b/ui/peacetrack.html -@@ -19,8 +19,7 @@ email : ranihaileydesai@gmail.com -

Graph

- - --

















-- {% include "footer.html" %} -+













- - - - -commit 7718a52a993761a387090cd76899b904422bcc4a -Author: desaivaibhavi -Date: Fri Aug 15 17:45:22 2014 +0530 - - many to many relationship done in summary - -diff --git a/ui/peacetrack.html b/ui/peacetrack.html -index 4f24747..06d946c 100644 ---- a/ui/peacetrack.html -+++ b/ui/peacetrack.html -@@ -14,9 +14,9 @@ email : ranihaileydesai@gmail.com - {% include "header.html" %} -





-
--

Summary

-+

Summary

-

Volunteer

--

Graph

-+

Graph

-
- -

















-diff --git a/ui/summary.html b/ui/summary.html -index edbffb6..3afa2c9 100644 ---- a/ui/summary.html -+++ b/ui/summary.html -@@ -30,7 +30,11 @@ email : ranihaileydesai@gmail.com - - Name of the post : {{post.post_name}}
- Region : {{post.post_region}}
-- Sector : {{post.sector}}
-+ Sector : -+ {% for item in post.sector.all() %} -+ {{ item }} -+ {% endfor %} -+
- {% endfor %} - - {% endif %} -diff --git a/ui/volunteer.html b/ui/volunteer.html -index 3c6cad8..340c5ea 100644 ---- a/ui/volunteer.html -+++ b/ui/volunteer.html -@@ -27,7 +27,7 @@ email : ranihaileydesai@gmail.com - - {% for vol in all_vol %} - -- Name of volunteer : {{vol.vol_name}}
-+ Name of volunteer : {{vol.vol_name}}
- Sector : {{vol.vol_sector}}
- Post : {{vol.vol_ptpost}}
- Activity : -@@ -45,7 +45,7 @@ email : ranihaileydesai@gmail.com - {{ item }} - {% endfor %} -
-- -+
- {% endfor %} - - {% endif %} - -commit f59b1a84fd453ae0dc6d7cf3762dfc75fe4e052b -Author: desaivaibhavi -Date: Fri Aug 15 17:40:18 2014 +0530 - - many to many relationship done in the volunteers - -diff --git a/ui/volunteer.html b/ui/volunteer.html -index bc8731a..3c6cad8 100644 ---- a/ui/volunteer.html -+++ b/ui/volunteer.html -@@ -30,17 +30,22 @@ email : ranihaileydesai@gmail.com - Name of volunteer : {{vol.vol_name}}
- Sector : {{vol.vol_sector}}
- Post : {{vol.vol_ptpost}}
-- Activity 1: -- -+ Activity : - {% for item in vol.vol_activity.all() %} - {{ item }} - {% endfor %} --
-- -- Activity : {{vol.vol_activity}}
-- Measurement : {{vol.vol_meas}}
-- Cohort : {{vol.vol_cohort}}
-
-+ Measurement : -+ {% for item in vol.vol_meas.all() %} -+ {{ item }} -+ {% endfor %} -+
-+ Cohort : -+ {% for item in vol.vol_cohort.all() %} -+ {{ item }} -+ {% endfor %} -+
-+ - {% endfor %} - - {% endif %} - -commit 45ee631f9b74d56125290bb216abe1e99888a347 -Author: desaivaibhavi -Date: Fri Aug 15 17:35:21 2014 +0530 - - many to many relationship - -diff --git a/ui/volunteer.html b/ui/volunteer.html -index 57ce0ff..bc8731a 100644 ---- a/ui/volunteer.html -+++ b/ui/volunteer.html -@@ -33,9 +33,9 @@ email : ranihaileydesai@gmail.com - Activity 1: - - {% for item in vol.vol_activity.all() %} -- item -+ {{ item }} - {% endfor %} -- -+
- - Activity : {{vol.vol_activity}}
- Measurement : {{vol.vol_meas}}
- -commit eb5755f5784a67b0f9374781a62abe054d74a8e8 -Author: desaivaibhavi -Date: Fri Aug 15 17:33:23 2014 +0530 - - many to many relationship - -diff --git a/ui/volunteer.html b/ui/volunteer.html -index 1b8838f..57ce0ff 100644 ---- a/ui/volunteer.html -+++ b/ui/volunteer.html -@@ -32,7 +32,7 @@ email : ranihaileydesai@gmail.com - Post : {{vol.vol_ptpost}}
- Activity 1: - -- {% for item in vol.vol_activity.all %} -+ {% for item in vol.vol_activity.all() %} - item - {% endfor %} - - -commit 0298ca250efc4ccea626e22ecd1f791d00ee3838 -Author: desaivaibhavi -Date: Fri Aug 15 17:30:49 2014 +0530 - - many to many relationship - -diff --git a/ui/volunteer.html b/ui/volunteer.html -index 1004652..1b8838f 100644 ---- a/ui/volunteer.html -+++ b/ui/volunteer.html -@@ -31,7 +31,7 @@ email : ranihaileydesai@gmail.com - Sector : {{vol.vol_sector}}
- Post : {{vol.vol_ptpost}}
- Activity 1: -- {{ vol.vol_activity | length }} -+ - {% for item in vol.vol_activity.all %} - item - {% endfor %} - -commit a5e7864b1a3afd36a09c863ac3179cb1a4efb41d -Author: desaivaibhavi -Date: Fri Aug 15 17:29:19 2014 +0530 - - many to many relationship - -diff --git a/ui/volunteer.html b/ui/volunteer.html -index f58f61f..1004652 100644 ---- a/ui/volunteer.html -+++ b/ui/volunteer.html -@@ -31,7 +31,10 @@ email : ranihaileydesai@gmail.com - Sector : {{vol.vol_sector}}
- Post : {{vol.vol_ptpost}}
- Activity 1: -- {{ vol.vol_activity.all }} -+ {{ vol.vol_activity | length }} -+ {% for item in vol.vol_activity.all %} -+ item -+ {% endfor %} - - - Activity : {{vol.vol_activity}}
- -commit 771ff3c4d5879e58e54ee66f2a0513a86a0935ff -Author: desaivaibhavi -Date: Fri Aug 15 17:18:14 2014 +0530 - - many to many relationship - -diff --git a/ui/volunteer.html b/ui/volunteer.html -index 9e46004..f58f61f 100644 ---- a/ui/volunteer.html -+++ b/ui/volunteer.html -@@ -31,7 +31,7 @@ email : ranihaileydesai@gmail.com - Sector : {{vol.vol_sector}}
- Post : {{vol.vol_ptpost}}
- Activity 1: -- {{ vol.vol_activity.all() }} -+ {{ vol.vol_activity.all }} - - - Activity : {{vol.vol_activity}}
- -commit 483789eb50187a306c610bb92f5028b67d90fb01 -Author: desaivaibhavi -Date: Fri Aug 15 17:15:11 2014 +0530 - - many to many relationship - -diff --git a/ui/volunteer.html b/ui/volunteer.html -index 1655a45..9e46004 100644 ---- a/ui/volunteer.html -+++ b/ui/volunteer.html -@@ -31,7 +31,7 @@ email : ranihaileydesai@gmail.com - Sector : {{vol.vol_sector}}
- Post : {{vol.vol_ptpost}}
- Activity 1: -- vol.vol_activity.all() -+ {{ vol.vol_activity.all() }} - - - Activity : {{vol.vol_activity}}
- -commit e488015e687e28bafd8a2c810a6eb476e839a23c -Author: desaivaibhavi -Date: Fri Aug 15 17:13:01 2014 +0530 - - many to many relationship - -diff --git a/ui/volunteer.html b/ui/volunteer.html -index a9a8c08..1655a45 100644 ---- a/ui/volunteer.html -+++ b/ui/volunteer.html -@@ -31,10 +31,8 @@ email : ranihaileydesai@gmail.com - Sector : {{vol.vol_sector}}
- Post : {{vol.vol_ptpost}}
- Activity 1: -- {% for act in vol.vol_activity %} -- {{ act}} -- {% endfor %} -- -+ vol.vol_activity.all() -+ - - Activity : {{vol.vol_activity}}
- Measurement : {{vol.vol_meas}}
- -commit 6734acf5de4f9b803185bb5818073bf0d66164cc -Author: desaivaibhavi -Date: Fri Aug 15 17:07:18 2014 +0530 - - many to many key - -diff --git a/ui/volunteer.html b/ui/volunteer.html -index 5d91b65..a9a8c08 100644 ---- a/ui/volunteer.html -+++ b/ui/volunteer.html -@@ -31,8 +31,8 @@ email : ranihaileydesai@gmail.com - Sector : {{vol.vol_sector}}
- Post : {{vol.vol_ptpost}}
- Activity 1: -- {% for activity in vol.vol_activity %} -- {{ activity}} -+ {% for act in vol.vol_activity %} -+ {{ act}} - {% endfor %} - - - -commit 5bf0faec5d90de805b3789c85e7333f7afb325a5 -Author: desaivaibhavi -Date: Fri Aug 15 14:42:31 2014 +0530 - - mane to many relationship - -diff --git a/ui/volunteer.html b/ui/volunteer.html -index 3b5f619..5d91b65 100644 ---- a/ui/volunteer.html -+++ b/ui/volunteer.html -@@ -30,6 +30,12 @@ email : ranihaileydesai@gmail.com - Name of volunteer : {{vol.vol_name}}
- Sector : {{vol.vol_sector}}
- Post : {{vol.vol_ptpost}}
-+ Activity 1: -+ {% for activity in vol.vol_activity %} -+ {{ activity}} -+ {% endfor %} -+ -+ - Activity : {{vol.vol_activity}}
- Measurement : {{vol.vol_meas}}
- Cohort : {{vol.vol_cohort}}
- -commit 548de08b94541a9b5b66370568982eb8e64dca01 -Author: desaivaibhavi -Date: Fri Aug 15 14:29:36 2014 +0530 - - changes in volunteer - -diff --git a/ui/volunteer.html b/ui/volunteer.html -index b2db704..3b5f619 100644 ---- a/ui/volunteer.html -+++ b/ui/volunteer.html -@@ -32,7 +32,7 @@ email : ranihaileydesai@gmail.com - Post : {{vol.vol_ptpost}}
- Activity : {{vol.vol_activity}}
- Measurement : {{vol.vol_meas}}
-- Cohurt : {{vol.vol_cohort}}
-+ Cohort : {{vol.vol_cohort}}
-
- {% endfor %} - -diff --git a/webhub/.~lock.Updated Project Framework Indicator List PeaceTrack.xlsx# b/webhub/.~lock.Updated Project Framework Indicator List PeaceTrack.xlsx# -new file mode 100644 -index 0000000..9a8992e ---- /dev/null -+++ b/webhub/.~lock.Updated Project Framework Indicator List PeaceTrack.xlsx# -@@ -0,0 +1 @@ -+,rani,rani-Inspiron-N4050,15.08.2014 13:55,file:///home/rani/.config/libreoffice/4; -\ No newline at end of file - -commit 66880ff6e6f4f8399c34d1c2eba3bb8e551b4858 -Author: desaivaibhavi -Date: Fri Aug 15 13:35:28 2014 +0530 - - profile bug solve - -diff --git a/ui/header.html b/ui/header.html -index 3f56eee..a0b464f 100644 ---- a/ui/header.html -+++ b/ui/header.html -@@ -27,7 +27,7 @@ email : ranihaileydesai@gmail.com - - {% if pcuser %} - - {% endif %} - -commit 99267c57d2585baab31044d764ef5ddf193d91be -Author: desaivaibhavi -Date: Fri Aug 15 06:17:03 2014 +0530 - - testing id - -diff --git a/ui/header.html b/ui/header.html -index a0b464f..3f56eee 100644 ---- a/ui/header.html -+++ b/ui/header.html -@@ -27,7 +27,7 @@ email : ranihaileydesai@gmail.com - - {% if pcuser %} - - {% endif %} - -commit 2af0be5257f4c07b4b6f67ddca94fc0c4b020b95 -Author: desaivaibhavi -Date: Fri Aug 15 05:43:57 2014 +0530 - - spell correct - -diff --git a/ui/newpost.html b/ui/newpost.html -index b282afc..a43b5f4 100644 ---- a/ui/newpost.html -+++ b/ui/newpost.html -@@ -36,7 +36,7 @@ email : ranihaileydesai@gmail.com -
-
-
--

Descrpition

-+

Description

-
-
- - -commit 5c83d90296b68e7309d5c7eac8779a80eed4ebe5 -Author: desaivaibhavi -Date: Fri Aug 15 05:39:10 2014 +0530 - - removing small bug in edit_profile - -diff --git a/webhub/views.py b/webhub/views.py -index 8e1f587..24b607d 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -1297,8 +1297,8 @@ def edit_profile(request): - - request.user.pcuser.gender = request.REQUEST['gender'] - request.user.pcuser.phone = request.REQUEST['phone'] -- request.user.pcuser.phone = request.REQUEST['email'] -- request.user.pcuser.gender = request.REQUEST['location'] -+ request.user.pcuser.email = request.REQUEST['email'] -+ request.user.pcuser.location = request.REQUEST['location'] - request.user.first_name = request.REQUEST['first_name'] - request.user.last_name = request.REQUEST['last_name'] - - -commit 08e348dfa759da81b7136f332154335c58378710 -Author: desaivaibhavi -Date: Fri Aug 15 04:25:00 2014 +0530 - - change in urls.py : cohort - -diff --git a/webhub/urls.py b/webhub/urls.py -index 4ded510..aeb9fcc 100644 ---- a/webhub/urls.py -+++ b/webhub/urls.py -@@ -23,7 +23,7 @@ router.register(r'outputs', views.OutputViewSet) - router.register(r'outcomes', views.OutcomeViewSet) - router.register(r'activity', views.ActivityViewSet) - router.register(r'measurement', views.MeasurementViewSet) --router.register(r'cohurt', views.CohurtViewSet) -+router.register(r'cohort', views.CohortViewSet) - router.register(r'volunteer', views.VolunteerViewSet) - - - -commit 01388998109039b4c1d9bb8d2ca881e6b08420e5 -Author: desaivaibhavi -Date: Fri Aug 15 04:22:48 2014 +0530 - - cohort spell correct - -diff --git a/webhub/serializers.py b/webhub/serializers.py -index 1c63074..3078879 100644 ---- a/webhub/serializers.py -+++ b/webhub/serializers.py -@@ -82,14 +82,14 @@ class ActivitySerializer(serializers.ModelSerializer): - class MeasurementSerializer(serializers.ModelSerializer): - class Meta: - model = Measurement -- fields = ('meas_title','meas_desc','meas_cohurt','meas_created','meas_outcome','id') -+ fields = ('meas_title','meas_desc','meas_cohort','meas_created','meas_outcome','id') - --class CohurtSerializer(serializers.ModelSerializer): -+class CohortSerializer(serializers.ModelSerializer): - class Meta: -- model = Cohurt -- fields = ('cohurt_name','cohurt_desc','cohurt_no_of_members','cohurt_age','cohurt_males','cohurt_females','cohurt_pos','cohurt_notes','id') -+ model = Cohort -+ fields = ('cohort_name','cohort_desc','cohort_no_of_members','cohort_age','cohort_males','cohort_females','cohort_pos','cohort_notes','id') - - class VolunteerSerializer(serializers.ModelSerializer): - class Meta: - model = Volunteer -- fields = ('vol_name','vol_sector','vol_ptpost','vol_activity','vol_meas','vol_cohurt','id') -\ No newline at end of file -+ fields = ('vol_name','vol_sector','vol_ptpost','vol_activity','vol_meas','vol_cohort','id') -\ No newline at end of file - -commit 45c476fcddff610930f8f12c350a4b235fdd643c -Author: desaivaibhavi -Date: Fri Aug 15 04:20:01 2014 +0530 - - cohort : spell correct - -diff --git a/webhub/serializers.py b/webhub/serializers.py -index 855e348..1c63074 100644 ---- a/webhub/serializers.py -+++ b/webhub/serializers.py -@@ -77,7 +77,7 @@ class OutcomeSerializer(serializers.ModelSerializer): - class ActivitySerializer(serializers.ModelSerializer): - class Meta: - model = Activity -- fields = ('activity_title','activity_desc','activity_cohurt','activity_created','activity_output','id') -+ fields = ('activity_title','activity_desc','activity_cohort','activity_created','activity_output','id') - - class MeasurementSerializer(serializers.ModelSerializer): - class Meta: -diff --git a/webhub/views.py b/webhub/views.py -index b29223a..8e1f587 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -704,50 +704,50 @@ def measurement_detail(request, pk): - - - --#for cohurts --class CohurtViewSet(viewsets.ModelViewSet): -+#for cohorts -+class CohortViewSet(viewsets.ModelViewSet): - """ - API endpoint that allows users to be viewed or edited. - """ -- queryset = Cohurt.objects.all() -- serializer_class = CohurtSerializer -+ queryset = Cohort.objects.all() -+ serializer_class = CohortSerializer - --#List all cohurt -+#List all cohort - @api_view(['GET', 'POST']) --def cohurt_list(request): -+def cohort_list(request): - if request.method == 'GET': -- cohurt = Cohurt.objects.all() -- serializer = CohurtSerializer(cohurt, many=True) -+ cohort = Cohort.objects.all() -+ serializer = CohortSerializer(cohort, many=True) - return Response(serializer.data) - - elif request.method == 'POST': -- serializer = CohurtSerializer(data=request.DATA) -+ serializer = CohortSerializer(data=request.DATA) - if serializer.is_valid(): - serializer.save() - return Response(serializer.data, status=status.HTTP_201_CREATED) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - --#Retrieve, update or delete a cohurt instance. -+#Retrieve, update or delete a cohort instance. - @api_view(['GET', 'PUT', 'DELETE']) --def cohurt_detail(request, pk): -+def cohort_detail(request, pk): - try: -- cohurt = Cohurt.objects.get(pk=pk) -+ cohort = Cohort.objects.get(pk=pk) - except Pcuser.DoesNotExist: - return Response(status=status.HTTP_404_NOT_FOUND) - - if request.method == 'GET': -- serializer = CohurtSerializer(cohurt) -+ serializer = CohortSerializer(cohort) - return Response(serializer.data) - - elif request.method == 'PUT': -- serializer = CohurtSerializer(cohurt, data=request.DATA) -+ serializer = CohortSerializer(cohort, data=request.DATA) - if serializer.is_valid(): - serializer.save() - return Response(serializer.data) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - - elif request.method == 'DELETE': -- cohurt.delete() -+ cohort.delete() - return Response(status=status.HTTP_204_NO_CONTENT) - - - -commit c88cc7106d41b6ad8f333c24dfa40e292c94fe8b -Author: desaivaibhavi -Date: Fri Aug 15 03:49:30 2014 +0530 - - cohort spelling corrected - -diff --git a/conf.py~ b/conf.py~ -new file mode 100644 -index 0000000..7c631fe ---- /dev/null -+++ b/conf.py~ -@@ -0,0 +1,263 @@ -+# -*- coding: utf-8 -*- -+# -+# systerspcweb documentation build configuration file, created by -+# sphinx-quickstart on Wed Aug 13 19:19:32 2014. -+# -+# This file is execfile()d with the current directory set to its -+# containing dir. -+# -+# Note that not all possible configuration values are present in this -+# autogenerated file. -+# -+# All configuration values have a default; values that are commented out -+# serve to show the default. -+ -+import sys -+import os -+ -+sys.path.insert(0,"home/rani/vdapp/webhub") -+ -+ -+# If extensions (or modules to document with autodoc) are in another directory, -+# add these directories to sys.path here. If the directory is relative to the -+# documentation root, use os.path.abspath to make it absolute, like shown here. -+#sys.path.insert(0, os.path.abspath('.')) -+ -+# -- General configuration ------------------------------------------------ -+ -+# If your documentation needs a minimal Sphinx version, state it here. -+#needs_sphinx = '1.0' -+ -+# Add any Sphinx extension module names here, as strings. They can be -+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -+# ones. -+extensions = [ -+ 'sphinx.ext.autodoc', -+] -+ -+# Add any paths that contain templates here, relative to this directory. -+templates_path = ['_templates'] -+ -+# The suffix of source filenames. -+source_suffix = '.txt' -+ -+# The encoding of source files. -+#source_encoding = 'utf-8-sig' -+ -+# The master toctree document. -+master_doc = 'systerspcweb_index' -+ -+# General information about the project. -+project = u'systerspcweb' -+copyright = u'2014, vaibhavi,rani' -+ -+# The version info for the project you're documenting, acts as replacement for -+# |version| and |release|, also used in various other places throughout the -+# built documents. -+# -+# The short X.Y version. -+version = '2.7' -+# The full version, including alpha/beta/rc tags. -+release = '2.7.6' -+ -+# The language for content autogenerated by Sphinx. Refer to documentation -+# for a list of supported languages. -+#language = None -+ -+# There are two options for replacing |today|: either, you set today to some -+# non-false value, then it is used: -+#today = '' -+# Else, today_fmt is used as the format for a strftime call. -+#today_fmt = '%B %d, %Y' -+ -+# List of patterns, relative to source directory, that match files and -+# directories to ignore when looking for source files. -+exclude_patterns = ['_build'] -+ -+# The reST default role (used for this markup: `text`) to use for all -+# documents. -+#default_role = None -+ -+# If true, '()' will be appended to :func: etc. cross-reference text. -+#add_function_parentheses = True -+ -+# If true, the current module name will be prepended to all description -+# unit titles (such as .. function::). -+#add_module_names = True -+ -+# If true, sectionauthor and moduleauthor directives will be shown in the -+# output. They are ignored by default. -+#show_authors = False -+ -+# The name of the Pygments (syntax highlighting) style to use. -+pygments_style = 'sphinx' -+ -+# A list of ignored prefixes for module index sorting. -+#modindex_common_prefix = [] -+ -+# If true, keep warnings as "system message" paragraphs in the built documents. -+#keep_warnings = False -+ -+ -+# -- Options for HTML output ---------------------------------------------- -+ -+# The theme to use for HTML and HTML Help pages. See the documentation for -+# a list of builtin themes. -+html_theme = 'default' -+ -+# Theme options are theme-specific and customize the look and feel of a theme -+# further. For a list of options available for each theme, see the -+# documentation. -+#html_theme_options = {} -+ -+# Add any paths that contain custom themes here, relative to this directory. -+#html_theme_path = [] -+ -+# The name for this set of Sphinx documents. If None, it defaults to -+# " v documentation". -+#html_title = None -+ -+# A shorter title for the navigation bar. Default is the same as html_title. -+#html_short_title = None -+ -+# The name of an image file (relative to this directory) to place at the top -+# of the sidebar. -+#html_logo = None -+ -+# The name of an image file (within the static path) to use as favicon of the -+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -+# pixels large. -+#html_favicon = None -+ -+# Add any paths that contain custom static files (such as style sheets) here, -+# relative to this directory. They are copied after the builtin static files, -+# so a file named "default.css" will overwrite the builtin "default.css". -+html_static_path = ['_static'] -+ -+# Add any extra paths that contain custom files (such as robots.txt or -+# .htaccess) here, relative to this directory. These files are copied -+# directly to the root of the documentation. -+#html_extra_path = [] -+ -+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -+# using the given strftime format. -+#html_last_updated_fmt = '%b %d, %Y' -+ -+# If true, SmartyPants will be used to convert quotes and dashes to -+# typographically correct entities. -+#html_use_smartypants = True -+ -+# Custom sidebar templates, maps document names to template names. -+#html_sidebars = {} -+ -+# Additional templates that should be rendered to pages, maps page names to -+# template names. -+#html_additional_pages = {} -+ -+# If false, no module index is generated. -+#html_domain_indices = True -+ -+# If false, no index is generated. -+#html_use_index = True -+ -+# If true, the index is split into individual pages for each letter. -+#html_split_index = False -+ -+# If true, links to the reST sources are added to the pages. -+#html_show_sourcelink = True -+ -+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -+#html_show_sphinx = True -+ -+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -+#html_show_copyright = True -+ -+# If true, an OpenSearch description file will be output, and all pages will -+# contain a tag referring to it. The value of this option must be the -+# base URL from which the finished HTML is served. -+#html_use_opensearch = '' -+ -+# This is the file name suffix for HTML files (e.g. ".xhtml"). -+#html_file_suffix = None -+ -+# Output file base name for HTML help builder. -+htmlhelp_basename = 'systerspcwebdoc' -+ -+ -+# -- Options for LaTeX output --------------------------------------------- -+ -+latex_elements = { -+# The paper size ('letterpaper' or 'a4paper'). -+#'papersize': 'letterpaper', -+ -+# The font size ('10pt', '11pt' or '12pt'). -+#'pointsize': '10pt', -+ -+# Additional stuff for the LaTeX preamble. -+#'preamble': '', -+} -+ -+# Grouping the document tree into LaTeX files. List of tuples -+# (source start file, target name, title, -+# author, documentclass [howto, manual, or own class]). -+latex_documents = [ -+ ('systerspcweb_index', 'systerspcweb.tex', u'systerspcweb Documentation', -+ u'vaibhavi,rani', 'manual'), -+] -+ -+# The name of an image file (relative to this directory) to place at the top of -+# the title page. -+#latex_logo = None -+ -+# For "manual" documents, if this is true, then toplevel headings are parts, -+# not chapters. -+#latex_use_parts = False -+ -+# If true, show page references after internal links. -+#latex_show_pagerefs = False -+ -+# If true, show URL addresses after external links. -+#latex_show_urls = False -+ -+# Documents to append as an appendix to all manuals. -+#latex_appendices = [] -+ -+# If false, no module index is generated. -+#latex_domain_indices = True -+ -+ -+# -- Options for manual page output --------------------------------------- -+ -+# One entry per manual page. List of tuples -+# (source start file, name, description, authors, manual section). -+man_pages = [ -+ ('systerspcweb_index', 'systerspcweb', u'systerspcweb Documentation', -+ [u'vaibhavi,rani'], 1) -+] -+ -+# If true, show URL addresses after external links. -+#man_show_urls = False -+ -+ -+# -- Options for Texinfo output ------------------------------------------- -+ -+# Grouping the document tree into Texinfo files. List of tuples -+# (source start file, target name, title, author, -+# dir menu entry, description, category) -+texinfo_documents = [ -+ ('systerspcweb_index', 'systerspcweb', u'systerspcweb Documentation', -+ u'vaibhavi,rani', 'systerspcweb', 'One line description of project.', -+ 'Miscellaneous'), -+] -+ -+# Documents to append as an appendix to all manuals. -+#texinfo_appendices = [] -+ -+# If false, no module index is generated. -+#texinfo_domain_indices = True -+ -+# How to display URL addresses: 'footnote', 'no', or 'inline'. -+#texinfo_show_urls = 'footnote' -+ -+# If true, do not generate a @detailmenu in the "Top" node's menu. -+#texinfo_no_detailmenu = False -diff --git a/infohub/__init__.pyc b/infohub/__init__.pyc -index 84f5574..402bca0 100644 -Binary files a/infohub/__init__.pyc and b/infohub/__init__.pyc differ -diff --git a/infohub/settings.pyc b/infohub/settings.pyc -index 4e57c2a..6f85e44 100644 -Binary files a/infohub/settings.pyc and b/infohub/settings.pyc differ -diff --git a/make.bat b/make.bat -new file mode 100644 -index 0000000..db50cfe ---- /dev/null -+++ b/make.bat -@@ -0,0 +1,242 @@ -+@ECHO OFF -+ -+REM Command file for Sphinx documentation -+ -+if "%SPHINXBUILD%" == "" ( -+ set SPHINXBUILD=sphinx-build -+) -+set BUILDDIR=_build -+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . -+set I18NSPHINXOPTS=%SPHINXOPTS% . -+if NOT "%PAPER%" == "" ( -+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% -+ set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% -+) -+ -+if "%1" == "" goto help -+ -+if "%1" == "help" ( -+ :help -+ echo.Please use `make ^` where ^ is one of -+ echo. html to make standalone HTML files -+ echo. dirhtml to make HTML files named index.html in directories -+ echo. singlehtml to make a single large HTML file -+ echo. pickle to make pickle files -+ echo. json to make JSON files -+ echo. htmlhelp to make HTML files and a HTML help project -+ echo. qthelp to make HTML files and a qthelp project -+ echo. devhelp to make HTML files and a Devhelp project -+ echo. epub to make an epub -+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter -+ echo. text to make text files -+ echo. man to make manual pages -+ echo. texinfo to make Texinfo files -+ echo. gettext to make PO message catalogs -+ echo. changes to make an overview over all changed/added/deprecated items -+ echo. xml to make Docutils-native XML files -+ echo. pseudoxml to make pseudoxml-XML files for display purposes -+ echo. linkcheck to check all external links for integrity -+ echo. doctest to run all doctests embedded in the documentation if enabled -+ goto end -+) -+ -+if "%1" == "clean" ( -+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i -+ del /q /s %BUILDDIR%\* -+ goto end -+) -+ -+ -+%SPHINXBUILD% 2> nul -+if errorlevel 9009 ( -+ echo. -+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx -+ echo.installed, then set the SPHINXBUILD environment variable to point -+ echo.to the full path of the 'sphinx-build' executable. Alternatively you -+ echo.may add the Sphinx directory to PATH. -+ echo. -+ echo.If you don't have Sphinx installed, grab it from -+ echo.http://sphinx-doc.org/ -+ exit /b 1 -+) -+ -+if "%1" == "html" ( -+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished. The HTML pages are in %BUILDDIR%/html. -+ goto end -+) -+ -+if "%1" == "dirhtml" ( -+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. -+ goto end -+) -+ -+if "%1" == "singlehtml" ( -+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. -+ goto end -+) -+ -+if "%1" == "pickle" ( -+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished; now you can process the pickle files. -+ goto end -+) -+ -+if "%1" == "json" ( -+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished; now you can process the JSON files. -+ goto end -+) -+ -+if "%1" == "htmlhelp" ( -+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished; now you can run HTML Help Workshop with the ^ -+.hhp project file in %BUILDDIR%/htmlhelp. -+ goto end -+) -+ -+if "%1" == "qthelp" ( -+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished; now you can run "qcollectiongenerator" with the ^ -+.qhcp project file in %BUILDDIR%/qthelp, like this: -+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\systerspcweb.qhcp -+ echo.To view the help file: -+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\systerspcweb.ghc -+ goto end -+) -+ -+if "%1" == "devhelp" ( -+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished. -+ goto end -+) -+ -+if "%1" == "epub" ( -+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished. The epub file is in %BUILDDIR%/epub. -+ goto end -+) -+ -+if "%1" == "latex" ( -+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. -+ goto end -+) -+ -+if "%1" == "latexpdf" ( -+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex -+ cd %BUILDDIR%/latex -+ make all-pdf -+ cd %BUILDDIR%/.. -+ echo. -+ echo.Build finished; the PDF files are in %BUILDDIR%/latex. -+ goto end -+) -+ -+if "%1" == "latexpdfja" ( -+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex -+ cd %BUILDDIR%/latex -+ make all-pdf-ja -+ cd %BUILDDIR%/.. -+ echo. -+ echo.Build finished; the PDF files are in %BUILDDIR%/latex. -+ goto end -+) -+ -+if "%1" == "text" ( -+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished. The text files are in %BUILDDIR%/text. -+ goto end -+) -+ -+if "%1" == "man" ( -+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished. The manual pages are in %BUILDDIR%/man. -+ goto end -+) -+ -+if "%1" == "texinfo" ( -+ %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. -+ goto end -+) -+ -+if "%1" == "gettext" ( -+ %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished. The message catalogs are in %BUILDDIR%/locale. -+ goto end -+) -+ -+if "%1" == "changes" ( -+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.The overview file is in %BUILDDIR%/changes. -+ goto end -+) -+ -+if "%1" == "linkcheck" ( -+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Link check complete; look for any errors in the above output ^ -+or in %BUILDDIR%/linkcheck/output.txt. -+ goto end -+) -+ -+if "%1" == "doctest" ( -+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Testing of doctests in the sources finished, look at the ^ -+results in %BUILDDIR%/doctest/output.txt. -+ goto end -+) -+ -+if "%1" == "xml" ( -+ %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished. The XML files are in %BUILDDIR%/xml. -+ goto end -+) -+ -+if "%1" == "pseudoxml" ( -+ %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. -+ goto end -+) -+ -+:end -diff --git a/systerspcweb_index.txt~ b/systerspcweb_index.txt~ -new file mode 100644 -index 0000000..b8e8524 ---- /dev/null -+++ b/systerspcweb_index.txt~ -@@ -0,0 +1,27 @@ -+.. systerspcweb documentation master file, created by -+ sphinx-quickstart on Wed Aug 13 19:19:32 2014. -+ You can adapt this file completely to your liking, but it should at least -+ contain the root `toctree` directive. -+ -+Welcome to systerspcweb's documentation! -+======================================== -+ -+Contents: -+ -+.. toctree:: -+ :maxdepth: 2 -+ -+.. automodule:: admin.py -+ -+.. autoclass:: UserSerializer -+ :members: -+ -+ -+ -+Indices and tables -+================== -+ -+* :ref:`genindex` -+* :ref:`modindex` -+* :ref:`search` -+ -diff --git a/ui/summary.html b/ui/summary.html -index 605c41b..edbffb6 100644 ---- a/ui/summary.html -+++ b/ui/summary.html -@@ -85,7 +85,7 @@ email : ranihaileydesai@gmail.com - Post : {{vol.vol_ptpost}}
- Activity : {{vol.vol_activity}}
- Measurement : {{vol.vol_meas}}
-- Cohurt : {{vol.vol_cohurt}}
-+ Cohurt : {{vol.vol_cohort}}
-
- {% endfor %} - -diff --git a/ui/volunteer.html b/ui/volunteer.html -index bae233b..b2db704 100644 ---- a/ui/volunteer.html -+++ b/ui/volunteer.html -@@ -32,7 +32,7 @@ email : ranihaileydesai@gmail.com - Post : {{vol.vol_ptpost}}
- Activity : {{vol.vol_activity}}
- Measurement : {{vol.vol_meas}}
-- Cohurt : {{vol.vol_cohurt}}
-+ Cohurt : {{vol.vol_cohort}}
-
- {% endfor %} - -diff --git a/webhub/Makefile b/webhub/Makefile -new file mode 100644 -index 0000000..942b466 ---- /dev/null -+++ b/webhub/Makefile -@@ -0,0 +1,177 @@ -+# Makefile for Sphinx documentation -+# -+ -+# You can set these variables from the command line. -+SPHINXOPTS = -+SPHINXBUILD = sphinx-build -+PAPER = -+BUILDDIR = _build -+ -+# User-friendly check for sphinx-build -+ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) -+$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) -+endif -+ -+# Internal variables. -+PAPEROPT_a4 = -D latex_paper_size=a4 -+PAPEROPT_letter = -D latex_paper_size=letter -+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -+# the i18n builder cannot share the environment and doctrees with the others -+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -+ -+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext -+ -+help: -+ @echo "Please use \`make ' where is one of" -+ @echo " html to make standalone HTML files" -+ @echo " dirhtml to make HTML files named index.html in directories" -+ @echo " singlehtml to make a single large HTML file" -+ @echo " pickle to make pickle files" -+ @echo " json to make JSON files" -+ @echo " htmlhelp to make HTML files and a HTML help project" -+ @echo " qthelp to make HTML files and a qthelp project" -+ @echo " devhelp to make HTML files and a Devhelp project" -+ @echo " epub to make an epub" -+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" -+ @echo " latexpdf to make LaTeX files and run them through pdflatex" -+ @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" -+ @echo " text to make text files" -+ @echo " man to make manual pages" -+ @echo " texinfo to make Texinfo files" -+ @echo " info to make Texinfo files and run them through makeinfo" -+ @echo " gettext to make PO message catalogs" -+ @echo " changes to make an overview of all changed/added/deprecated items" -+ @echo " xml to make Docutils-native XML files" -+ @echo " pseudoxml to make pseudoxml-XML files for display purposes" -+ @echo " linkcheck to check all external links for integrity" -+ @echo " doctest to run all doctests embedded in the documentation (if enabled)" -+ -+clean: -+ rm -rf $(BUILDDIR)/* -+ -+html: -+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html -+ @echo -+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." -+ -+dirhtml: -+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml -+ @echo -+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." -+ -+singlehtml: -+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml -+ @echo -+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." -+ -+pickle: -+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle -+ @echo -+ @echo "Build finished; now you can process the pickle files." -+ -+json: -+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json -+ @echo -+ @echo "Build finished; now you can process the JSON files." -+ -+htmlhelp: -+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp -+ @echo -+ @echo "Build finished; now you can run HTML Help Workshop with the" \ -+ ".hhp project file in $(BUILDDIR)/htmlhelp." -+ -+qthelp: -+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp -+ @echo -+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \ -+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" -+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/systerspcweb.qhcp" -+ @echo "To view the help file:" -+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/systerspcweb.qhc" -+ -+devhelp: -+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp -+ @echo -+ @echo "Build finished." -+ @echo "To view the help file:" -+ @echo "# mkdir -p $$HOME/.local/share/devhelp/systerspcweb" -+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/systerspcweb" -+ @echo "# devhelp" -+ -+epub: -+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub -+ @echo -+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub." -+ -+latex: -+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex -+ @echo -+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." -+ @echo "Run \`make' in that directory to run these through (pdf)latex" \ -+ "(use \`make latexpdf' here to do that automatically)." -+ -+latexpdf: -+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex -+ @echo "Running LaTeX files through pdflatex..." -+ $(MAKE) -C $(BUILDDIR)/latex all-pdf -+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." -+ -+latexpdfja: -+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex -+ @echo "Running LaTeX files through platex and dvipdfmx..." -+ $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja -+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." -+ -+text: -+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text -+ @echo -+ @echo "Build finished. The text files are in $(BUILDDIR)/text." -+ -+man: -+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man -+ @echo -+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man." -+ -+texinfo: -+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo -+ @echo -+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." -+ @echo "Run \`make' in that directory to run these through makeinfo" \ -+ "(use \`make info' here to do that automatically)." -+ -+info: -+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo -+ @echo "Running Texinfo files through makeinfo..." -+ make -C $(BUILDDIR)/texinfo info -+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." -+ -+gettext: -+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale -+ @echo -+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." -+ -+changes: -+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes -+ @echo -+ @echo "The overview file is in $(BUILDDIR)/changes." -+ -+linkcheck: -+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck -+ @echo -+ @echo "Link check complete; look for any errors in the above output " \ -+ "or in $(BUILDDIR)/linkcheck/output.txt." -+ -+doctest: -+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest -+ @echo "Testing of doctests in the sources finished, look at the " \ -+ "results in $(BUILDDIR)/doctest/output.txt." -+ -+xml: -+ $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml -+ @echo -+ @echo "Build finished. The XML files are in $(BUILDDIR)/xml." -+ -+pseudoxml: -+ $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml -+ @echo -+ @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." -diff --git a/webhub/_build/doctrees/environment.pickle b/webhub/_build/doctrees/environment.pickle -new file mode 100644 -index 0000000..4a369e0 -Binary files /dev/null and b/webhub/_build/doctrees/environment.pickle differ -diff --git a/webhub/_build/doctrees/systerspcweb.doctree b/webhub/_build/doctrees/systerspcweb.doctree -new file mode 100644 -index 0000000..ec973ac -Binary files /dev/null and b/webhub/_build/doctrees/systerspcweb.doctree differ -diff --git a/webhub/_build/html/.buildinfo b/webhub/_build/html/.buildinfo -new file mode 100644 -index 0000000..564c89b ---- /dev/null -+++ b/webhub/_build/html/.buildinfo -@@ -0,0 +1,4 @@ -+# Sphinx build info version 1 -+# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -+config: badb373ed0d498a883c1ed6b8d08ef26 -+tags: 645f666f9bcd5a90fca523b33c5a78b7 -diff --git a/webhub/_build/html/_sources/systerspcweb.txt b/webhub/_build/html/_sources/systerspcweb.txt -new file mode 100644 -index 0000000..01325ed ---- /dev/null -+++ b/webhub/_build/html/_sources/systerspcweb.txt -@@ -0,0 +1,26 @@ -+.. systerspcweb documentation master file, created by -+ sphinx-quickstart on Wed Aug 13 20:07:49 2014. -+ You can adapt this file completely to your liking, but it should at least -+ contain the root `toctree` directive. -+ -+Welcome to systerspcweb's documentation! -+======================================== -+ -+Contents: -+ -+.. toctree:: -+ :maxdepth: 2 -+ -+.. automodule:: serializers.py -+ -+.. autoclass:: UserSerializer -+ :members: -+ -+ -+Indices and tables -+================== -+ -+* :ref:`genindex` -+* :ref:`modindex` -+* :ref:`search` -+ -diff --git a/webhub/_build/html/_static/ajax-loader.gif b/webhub/_build/html/_static/ajax-loader.gif -new file mode 100644 -index 0000000..61faf8c -Binary files /dev/null and b/webhub/_build/html/_static/ajax-loader.gif differ -diff --git a/webhub/_build/html/_static/basic.css b/webhub/_build/html/_static/basic.css -new file mode 100644 -index 0000000..967e36c ---- /dev/null -+++ b/webhub/_build/html/_static/basic.css -@@ -0,0 +1,537 @@ -+/* -+ * basic.css -+ * ~~~~~~~~~ -+ * -+ * Sphinx stylesheet -- basic theme. -+ * -+ * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. -+ * :license: BSD, see LICENSE for details. -+ * -+ */ -+ -+/* -- main layout ----------------------------------------------------------- */ -+ -+div.clearer { -+ clear: both; -+} -+ -+/* -- relbar ---------------------------------------------------------------- */ -+ -+div.related { -+ width: 100%; -+ font-size: 90%; -+} -+ -+div.related h3 { -+ display: none; -+} -+ -+div.related ul { -+ margin: 0; -+ padding: 0 0 0 10px; -+ list-style: none; -+} -+ -+div.related li { -+ display: inline; -+} -+ -+div.related li.right { -+ float: right; -+ margin-right: 5px; -+} -+ -+/* -- sidebar --------------------------------------------------------------- */ -+ -+div.sphinxsidebarwrapper { -+ padding: 10px 5px 0 10px; -+} -+ -+div.sphinxsidebar { -+ float: left; -+ width: 230px; -+ margin-left: -100%; -+ font-size: 90%; -+} -+ -+div.sphinxsidebar ul { -+ list-style: none; -+} -+ -+div.sphinxsidebar ul ul, -+div.sphinxsidebar ul.want-points { -+ margin-left: 20px; -+ list-style: square; -+} -+ -+div.sphinxsidebar ul ul { -+ margin-top: 0; -+ margin-bottom: 0; -+} -+ -+div.sphinxsidebar form { -+ margin-top: 10px; -+} -+ -+div.sphinxsidebar input { -+ border: 1px solid #98dbcc; -+ font-family: sans-serif; -+ font-size: 1em; -+} -+ -+div.sphinxsidebar #searchbox input[type="text"] { -+ width: 170px; -+} -+ -+div.sphinxsidebar #searchbox input[type="submit"] { -+ width: 30px; -+} -+ -+img { -+ border: 0; -+ max-width: 100%; -+} -+ -+/* -- search page ----------------------------------------------------------- */ -+ -+ul.search { -+ margin: 10px 0 0 20px; -+ padding: 0; -+} -+ -+ul.search li { -+ padding: 5px 0 5px 20px; -+ background-image: url(file.png); -+ background-repeat: no-repeat; -+ background-position: 0 7px; -+} -+ -+ul.search li a { -+ font-weight: bold; -+} -+ -+ul.search li div.context { -+ color: #888; -+ margin: 2px 0 0 30px; -+ text-align: left; -+} -+ -+ul.keywordmatches li.goodmatch a { -+ font-weight: bold; -+} -+ -+/* -- index page ------------------------------------------------------------ */ -+ -+table.contentstable { -+ width: 90%; -+} -+ -+table.contentstable p.biglink { -+ line-height: 150%; -+} -+ -+a.biglink { -+ font-size: 1.3em; -+} -+ -+span.linkdescr { -+ font-style: italic; -+ padding-top: 5px; -+ font-size: 90%; -+} -+ -+/* -- general index --------------------------------------------------------- */ -+ -+table.indextable { -+ width: 100%; -+} -+ -+table.indextable td { -+ text-align: left; -+ vertical-align: top; -+} -+ -+table.indextable dl, table.indextable dd { -+ margin-top: 0; -+ margin-bottom: 0; -+} -+ -+table.indextable tr.pcap { -+ height: 10px; -+} -+ -+table.indextable tr.cap { -+ margin-top: 10px; -+ background-color: #f2f2f2; -+} -+ -+img.toggler { -+ margin-right: 3px; -+ margin-top: 3px; -+ cursor: pointer; -+} -+ -+div.modindex-jumpbox { -+ border-top: 1px solid #ddd; -+ border-bottom: 1px solid #ddd; -+ margin: 1em 0 1em 0; -+ padding: 0.4em; -+} -+ -+div.genindex-jumpbox { -+ border-top: 1px solid #ddd; -+ border-bottom: 1px solid #ddd; -+ margin: 1em 0 1em 0; -+ padding: 0.4em; -+} -+ -+/* -- general body styles --------------------------------------------------- */ -+ -+a.headerlink { -+ visibility: hidden; -+} -+ -+h1:hover > a.headerlink, -+h2:hover > a.headerlink, -+h3:hover > a.headerlink, -+h4:hover > a.headerlink, -+h5:hover > a.headerlink, -+h6:hover > a.headerlink, -+dt:hover > a.headerlink { -+ visibility: visible; -+} -+ -+div.body p.caption { -+ text-align: inherit; -+} -+ -+div.body td { -+ text-align: left; -+} -+ -+.field-list ul { -+ padding-left: 1em; -+} -+ -+.first { -+ margin-top: 0 !important; -+} -+ -+p.rubric { -+ margin-top: 30px; -+ font-weight: bold; -+} -+ -+img.align-left, .figure.align-left, object.align-left { -+ clear: left; -+ float: left; -+ margin-right: 1em; -+} -+ -+img.align-right, .figure.align-right, object.align-right { -+ clear: right; -+ float: right; -+ margin-left: 1em; -+} -+ -+img.align-center, .figure.align-center, object.align-center { -+ display: block; -+ margin-left: auto; -+ margin-right: auto; -+} -+ -+.align-left { -+ text-align: left; -+} -+ -+.align-center { -+ text-align: center; -+} -+ -+.align-right { -+ text-align: right; -+} -+ -+/* -- sidebars -------------------------------------------------------------- */ -+ -+div.sidebar { -+ margin: 0 0 0.5em 1em; -+ border: 1px solid #ddb; -+ padding: 7px 7px 0 7px; -+ background-color: #ffe; -+ width: 40%; -+ float: right; -+} -+ -+p.sidebar-title { -+ font-weight: bold; -+} -+ -+/* -- topics ---------------------------------------------------------------- */ -+ -+div.topic { -+ border: 1px solid #ccc; -+ padding: 7px 7px 0 7px; -+ margin: 10px 0 10px 0; -+} -+ -+p.topic-title { -+ font-size: 1.1em; -+ font-weight: bold; -+ margin-top: 10px; -+} -+ -+/* -- admonitions ----------------------------------------------------------- */ -+ -+div.admonition { -+ margin-top: 10px; -+ margin-bottom: 10px; -+ padding: 7px; -+} -+ -+div.admonition dt { -+ font-weight: bold; -+} -+ -+div.admonition dl { -+ margin-bottom: 0; -+} -+ -+p.admonition-title { -+ margin: 0px 10px 5px 0px; -+ font-weight: bold; -+} -+ -+div.body p.centered { -+ text-align: center; -+ margin-top: 25px; -+} -+ -+/* -- tables ---------------------------------------------------------------- */ -+ -+table.docutils { -+ border: 0; -+ border-collapse: collapse; -+} -+ -+table.docutils td, table.docutils th { -+ padding: 1px 8px 1px 5px; -+ border-top: 0; -+ border-left: 0; -+ border-right: 0; -+ border-bottom: 1px solid #aaa; -+} -+ -+table.field-list td, table.field-list th { -+ border: 0 !important; -+} -+ -+table.footnote td, table.footnote th { -+ border: 0 !important; -+} -+ -+th { -+ text-align: left; -+ padding-right: 5px; -+} -+ -+table.citation { -+ border-left: solid 1px gray; -+ margin-left: 1px; -+} -+ -+table.citation td { -+ border-bottom: none; -+} -+ -+/* -- other body styles ----------------------------------------------------- */ -+ -+ol.arabic { -+ list-style: decimal; -+} -+ -+ol.loweralpha { -+ list-style: lower-alpha; -+} -+ -+ol.upperalpha { -+ list-style: upper-alpha; -+} -+ -+ol.lowerroman { -+ list-style: lower-roman; -+} -+ -+ol.upperroman { -+ list-style: upper-roman; -+} -+ -+dl { -+ margin-bottom: 15px; -+} -+ -+dd p { -+ margin-top: 0px; -+} -+ -+dd ul, dd table { -+ margin-bottom: 10px; -+} -+ -+dd { -+ margin-top: 3px; -+ margin-bottom: 10px; -+ margin-left: 30px; -+} -+ -+dt:target, .highlighted { -+ background-color: #fbe54e; -+} -+ -+dl.glossary dt { -+ font-weight: bold; -+ font-size: 1.1em; -+} -+ -+.field-list ul { -+ margin: 0; -+ padding-left: 1em; -+} -+ -+.field-list p { -+ margin: 0; -+} -+ -+.optional { -+ font-size: 1.3em; -+} -+ -+.versionmodified { -+ font-style: italic; -+} -+ -+.system-message { -+ background-color: #fda; -+ padding: 5px; -+ border: 3px solid red; -+} -+ -+.footnote:target { -+ background-color: #ffa; -+} -+ -+.line-block { -+ display: block; -+ margin-top: 1em; -+ margin-bottom: 1em; -+} -+ -+.line-block .line-block { -+ margin-top: 0; -+ margin-bottom: 0; -+ margin-left: 1.5em; -+} -+ -+.guilabel, .menuselection { -+ font-family: sans-serif; -+} -+ -+.accelerator { -+ text-decoration: underline; -+} -+ -+.classifier { -+ font-style: oblique; -+} -+ -+abbr, acronym { -+ border-bottom: dotted 1px; -+ cursor: help; -+} -+ -+/* -- code displays --------------------------------------------------------- */ -+ -+pre { -+ overflow: auto; -+ overflow-y: hidden; /* fixes display issues on Chrome browsers */ -+} -+ -+td.linenos pre { -+ padding: 5px 0px; -+ border: 0; -+ background-color: transparent; -+ color: #aaa; -+} -+ -+table.highlighttable { -+ margin-left: 0.5em; -+} -+ -+table.highlighttable td { -+ padding: 0 0.5em 0 0.5em; -+} -+ -+tt.descname { -+ background-color: transparent; -+ font-weight: bold; -+ font-size: 1.2em; -+} -+ -+tt.descclassname { -+ background-color: transparent; -+} -+ -+tt.xref, a tt { -+ background-color: transparent; -+ font-weight: bold; -+} -+ -+h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { -+ background-color: transparent; -+} -+ -+.viewcode-link { -+ float: right; -+} -+ -+.viewcode-back { -+ float: right; -+ font-family: sans-serif; -+} -+ -+div.viewcode-block:target { -+ margin: -1px -10px; -+ padding: 0 10px; -+} -+ -+/* -- math display ---------------------------------------------------------- */ -+ -+img.math { -+ vertical-align: middle; -+} -+ -+div.body div.math p { -+ text-align: center; -+} -+ -+span.eqno { -+ float: right; -+} -+ -+/* -- printout stylesheet --------------------------------------------------- */ -+ -+@media print { -+ div.document, -+ div.documentwrapper, -+ div.bodywrapper { -+ margin: 0 !important; -+ width: 100%; -+ } -+ -+ div.sphinxsidebar, -+ div.related, -+ div.footer, -+ #top-link { -+ display: none; -+ } -+} -\ No newline at end of file -diff --git a/webhub/_build/html/_static/comment-bright.png b/webhub/_build/html/_static/comment-bright.png -new file mode 100644 -index 0000000..551517b -Binary files /dev/null and b/webhub/_build/html/_static/comment-bright.png differ -diff --git a/webhub/_build/html/_static/comment-close.png b/webhub/_build/html/_static/comment-close.png -new file mode 100644 -index 0000000..09b54be -Binary files /dev/null and b/webhub/_build/html/_static/comment-close.png differ -diff --git a/webhub/_build/html/_static/comment.png b/webhub/_build/html/_static/comment.png -new file mode 100644 -index 0000000..92feb52 -Binary files /dev/null and b/webhub/_build/html/_static/comment.png differ -diff --git a/webhub/_build/html/_static/default.css b/webhub/_build/html/_static/default.css -new file mode 100644 -index 0000000..5f1399a ---- /dev/null -+++ b/webhub/_build/html/_static/default.css -@@ -0,0 +1,256 @@ -+/* -+ * default.css_t -+ * ~~~~~~~~~~~~~ -+ * -+ * Sphinx stylesheet -- default theme. -+ * -+ * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. -+ * :license: BSD, see LICENSE for details. -+ * -+ */ -+ -+@import url("basic.css"); -+ -+/* -- page layout ----------------------------------------------------------- */ -+ -+body { -+ font-family: sans-serif; -+ font-size: 100%; -+ background-color: #11303d; -+ color: #000; -+ margin: 0; -+ padding: 0; -+} -+ -+div.document { -+ background-color: #1c4e63; -+} -+ -+div.documentwrapper { -+ float: left; -+ width: 100%; -+} -+ -+div.bodywrapper { -+ margin: 0 0 0 230px; -+} -+ -+div.body { -+ background-color: #ffffff; -+ color: #000000; -+ padding: 0 20px 30px 20px; -+} -+ -+div.footer { -+ color: #ffffff; -+ width: 100%; -+ padding: 9px 0 9px 0; -+ text-align: center; -+ font-size: 75%; -+} -+ -+div.footer a { -+ color: #ffffff; -+ text-decoration: underline; -+} -+ -+div.related { -+ background-color: #133f52; -+ line-height: 30px; -+ color: #ffffff; -+} -+ -+div.related a { -+ color: #ffffff; -+} -+ -+div.sphinxsidebar { -+} -+ -+div.sphinxsidebar h3 { -+ font-family: 'Trebuchet MS', sans-serif; -+ color: #ffffff; -+ font-size: 1.4em; -+ font-weight: normal; -+ margin: 0; -+ padding: 0; -+} -+ -+div.sphinxsidebar h3 a { -+ color: #ffffff; -+} -+ -+div.sphinxsidebar h4 { -+ font-family: 'Trebuchet MS', sans-serif; -+ color: #ffffff; -+ font-size: 1.3em; -+ font-weight: normal; -+ margin: 5px 0 0 0; -+ padding: 0; -+} -+ -+div.sphinxsidebar p { -+ color: #ffffff; -+} -+ -+div.sphinxsidebar p.topless { -+ margin: 5px 10px 10px 10px; -+} -+ -+div.sphinxsidebar ul { -+ margin: 10px; -+ padding: 0; -+ color: #ffffff; -+} -+ -+div.sphinxsidebar a { -+ color: #98dbcc; -+} -+ -+div.sphinxsidebar input { -+ border: 1px solid #98dbcc; -+ font-family: sans-serif; -+ font-size: 1em; -+} -+ -+ -+ -+/* -- hyperlink styles ------------------------------------------------------ */ -+ -+a { -+ color: #355f7c; -+ text-decoration: none; -+} -+ -+a:visited { -+ color: #355f7c; -+ text-decoration: none; -+} -+ -+a:hover { -+ text-decoration: underline; -+} -+ -+ -+ -+/* -- body styles ----------------------------------------------------------- */ -+ -+div.body h1, -+div.body h2, -+div.body h3, -+div.body h4, -+div.body h5, -+div.body h6 { -+ font-family: 'Trebuchet MS', sans-serif; -+ background-color: #f2f2f2; -+ font-weight: normal; -+ color: #20435c; -+ border-bottom: 1px solid #ccc; -+ margin: 20px -20px 10px -20px; -+ padding: 3px 0 3px 10px; -+} -+ -+div.body h1 { margin-top: 0; font-size: 200%; } -+div.body h2 { font-size: 160%; } -+div.body h3 { font-size: 140%; } -+div.body h4 { font-size: 120%; } -+div.body h5 { font-size: 110%; } -+div.body h6 { font-size: 100%; } -+ -+a.headerlink { -+ color: #c60f0f; -+ font-size: 0.8em; -+ padding: 0 4px 0 4px; -+ text-decoration: none; -+} -+ -+a.headerlink:hover { -+ background-color: #c60f0f; -+ color: white; -+} -+ -+div.body p, div.body dd, div.body li { -+ text-align: justify; -+ line-height: 130%; -+} -+ -+div.admonition p.admonition-title + p { -+ display: inline; -+} -+ -+div.admonition p { -+ margin-bottom: 5px; -+} -+ -+div.admonition pre { -+ margin-bottom: 5px; -+} -+ -+div.admonition ul, div.admonition ol { -+ margin-bottom: 5px; -+} -+ -+div.note { -+ background-color: #eee; -+ border: 1px solid #ccc; -+} -+ -+div.seealso { -+ background-color: #ffc; -+ border: 1px solid #ff6; -+} -+ -+div.topic { -+ background-color: #eee; -+} -+ -+div.warning { -+ background-color: #ffe4e4; -+ border: 1px solid #f66; -+} -+ -+p.admonition-title { -+ display: inline; -+} -+ -+p.admonition-title:after { -+ content: ":"; -+} -+ -+pre { -+ padding: 5px; -+ background-color: #eeffcc; -+ color: #333333; -+ line-height: 120%; -+ border: 1px solid #ac9; -+ border-left: none; -+ border-right: none; -+} -+ -+tt { -+ background-color: #ecf0f3; -+ padding: 0 1px 0 1px; -+ font-size: 0.95em; -+} -+ -+th { -+ background-color: #ede; -+} -+ -+.warning tt { -+ background: #efc2c2; -+} -+ -+.note tt { -+ background: #d6d6d6; -+} -+ -+.viewcode-back { -+ font-family: sans-serif; -+} -+ -+div.viewcode-block:target { -+ background-color: #f4debf; -+ border-top: 1px solid #ac9; -+ border-bottom: 1px solid #ac9; -+} -\ No newline at end of file -diff --git a/webhub/_build/html/_static/doctools.js b/webhub/_build/html/_static/doctools.js -new file mode 100644 -index 0000000..c5455c9 ---- /dev/null -+++ b/webhub/_build/html/_static/doctools.js -@@ -0,0 +1,238 @@ -+/* -+ * doctools.js -+ * ~~~~~~~~~~~ -+ * -+ * Sphinx JavaScript utilities for all documentation. -+ * -+ * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. -+ * :license: BSD, see LICENSE for details. -+ * -+ */ -+ -+/** -+ * select a different prefix for underscore -+ */ -+$u = _.noConflict(); -+ -+/** -+ * make the code below compatible with browsers without -+ * an installed firebug like debugger -+if (!window.console || !console.firebug) { -+ var names = ["log", "debug", "info", "warn", "error", "assert", "dir", -+ "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", -+ "profile", "profileEnd"]; -+ window.console = {}; -+ for (var i = 0; i < names.length; ++i) -+ window.console[names[i]] = function() {}; -+} -+ */ -+ -+/** -+ * small helper function to urldecode strings -+ */ -+jQuery.urldecode = function(x) { -+ return decodeURIComponent(x).replace(/\+/g, ' '); -+}; -+ -+/** -+ * small helper function to urlencode strings -+ */ -+jQuery.urlencode = encodeURIComponent; -+ -+/** -+ * This function returns the parsed url parameters of the -+ * current request. Multiple values per key are supported, -+ * it will always return arrays of strings for the value parts. -+ */ -+jQuery.getQueryParameters = function(s) { -+ if (typeof s == 'undefined') -+ s = document.location.search; -+ var parts = s.substr(s.indexOf('?') + 1).split('&'); -+ var result = {}; -+ for (var i = 0; i < parts.length; i++) { -+ var tmp = parts[i].split('=', 2); -+ var key = jQuery.urldecode(tmp[0]); -+ var value = jQuery.urldecode(tmp[1]); -+ if (key in result) -+ result[key].push(value); -+ else -+ result[key] = [value]; -+ } -+ return result; -+}; -+ -+/** -+ * highlight a given string on a jquery object by wrapping it in -+ * span elements with the given class name. -+ */ -+jQuery.fn.highlightText = function(text, className) { -+ function highlight(node) { -+ if (node.nodeType == 3) { -+ var val = node.nodeValue; -+ var pos = val.toLowerCase().indexOf(text); -+ if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { -+ var span = document.createElement("span"); -+ span.className = className; -+ span.appendChild(document.createTextNode(val.substr(pos, text.length))); -+ node.parentNode.insertBefore(span, node.parentNode.insertBefore( -+ document.createTextNode(val.substr(pos + text.length)), -+ node.nextSibling)); -+ node.nodeValue = val.substr(0, pos); -+ } -+ } -+ else if (!jQuery(node).is("button, select, textarea")) { -+ jQuery.each(node.childNodes, function() { -+ highlight(this); -+ }); -+ } -+ } -+ return this.each(function() { -+ highlight(this); -+ }); -+}; -+ -+/** -+ * Small JavaScript module for the documentation. -+ */ -+var Documentation = { -+ -+ init : function() { -+ this.fixFirefoxAnchorBug(); -+ this.highlightSearchWords(); -+ this.initIndexTable(); -+ }, -+ -+ /** -+ * i18n support -+ */ -+ TRANSLATIONS : {}, -+ PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, -+ LOCALE : 'unknown', -+ -+ // gettext and ngettext don't access this so that the functions -+ // can safely bound to a different name (_ = Documentation.gettext) -+ gettext : function(string) { -+ var translated = Documentation.TRANSLATIONS[string]; -+ if (typeof translated == 'undefined') -+ return string; -+ return (typeof translated == 'string') ? translated : translated[0]; -+ }, -+ -+ ngettext : function(singular, plural, n) { -+ var translated = Documentation.TRANSLATIONS[singular]; -+ if (typeof translated == 'undefined') -+ return (n == 1) ? singular : plural; -+ return translated[Documentation.PLURALEXPR(n)]; -+ }, -+ -+ addTranslations : function(catalog) { -+ for (var key in catalog.messages) -+ this.TRANSLATIONS[key] = catalog.messages[key]; -+ this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); -+ this.LOCALE = catalog.locale; -+ }, -+ -+ /** -+ * add context elements like header anchor links -+ */ -+ addContextElements : function() { -+ $('div[id] > :header:first').each(function() { -+ $('\u00B6'). -+ attr('href', '#' + this.id). -+ attr('title', _('Permalink to this headline')). -+ appendTo(this); -+ }); -+ $('dt[id]').each(function() { -+ $('\u00B6'). -+ attr('href', '#' + this.id). -+ attr('title', _('Permalink to this definition')). -+ appendTo(this); -+ }); -+ }, -+ -+ /** -+ * workaround a firefox stupidity -+ */ -+ fixFirefoxAnchorBug : function() { -+ if (document.location.hash && $.browser.mozilla) -+ window.setTimeout(function() { -+ document.location.href += ''; -+ }, 10); -+ }, -+ -+ /** -+ * highlight the search words provided in the url in the text -+ */ -+ highlightSearchWords : function() { -+ var params = $.getQueryParameters(); -+ var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; -+ if (terms.length) { -+ var body = $('div.body'); -+ if (!body.length) { -+ body = $('body'); -+ } -+ window.setTimeout(function() { -+ $.each(terms, function() { -+ body.highlightText(this.toLowerCase(), 'highlighted'); -+ }); -+ }, 10); -+ $('') -+ .appendTo($('#searchbox')); -+ } -+ }, -+ -+ /** -+ * init the domain index toggle buttons -+ */ -+ initIndexTable : function() { -+ var togglers = $('img.toggler').click(function() { -+ var src = $(this).attr('src'); -+ var idnum = $(this).attr('id').substr(7); -+ $('tr.cg-' + idnum).toggle(); -+ if (src.substr(-9) == 'minus.png') -+ $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); -+ else -+ $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); -+ }).css('display', ''); -+ if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { -+ togglers.click(); -+ } -+ }, -+ -+ /** -+ * helper function to hide the search marks again -+ */ -+ hideSearchWords : function() { -+ $('#searchbox .highlight-link').fadeOut(300); -+ $('span.highlighted').removeClass('highlighted'); -+ }, -+ -+ /** -+ * make the url absolute -+ */ -+ makeURL : function(relativeURL) { -+ return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; -+ }, -+ -+ /** -+ * get the current relative url -+ */ -+ getCurrentURL : function() { -+ var path = document.location.pathname; -+ var parts = path.split(/\//); -+ $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { -+ if (this == '..') -+ parts.pop(); -+ }); -+ var url = parts.join('/'); -+ return path.substring(url.lastIndexOf('/') + 1, path.length - 1); -+ } -+}; -+ -+// quick alias for translations -+_ = Documentation.gettext; -+ -+$(document).ready(function() { -+ Documentation.init(); -+}); -diff --git a/webhub/_build/html/_static/down-pressed.png b/webhub/_build/html/_static/down-pressed.png -new file mode 100644 -index 0000000..6f7ad78 -Binary files /dev/null and b/webhub/_build/html/_static/down-pressed.png differ -diff --git a/webhub/_build/html/_static/down.png b/webhub/_build/html/_static/down.png -new file mode 100644 -index 0000000..3003a88 -Binary files /dev/null and b/webhub/_build/html/_static/down.png differ -diff --git a/webhub/_build/html/_static/file.png b/webhub/_build/html/_static/file.png -new file mode 100644 -index 0000000..d18082e -Binary files /dev/null and b/webhub/_build/html/_static/file.png differ -diff --git a/webhub/_build/html/_static/jquery.js b/webhub/_build/html/_static/jquery.js -new file mode 100644 -index 0000000..e2efc33 ---- /dev/null -+++ b/webhub/_build/html/_static/jquery.js -@@ -0,0 +1,9404 @@ -+/*! -+ * jQuery JavaScript Library v1.7.2 -+ * http://jquery.com/ -+ * -+ * Copyright 2011, John Resig -+ * Dual licensed under the MIT or GPL Version 2 licenses. -+ * http://jquery.org/license -+ * -+ * Includes Sizzle.js -+ * http://sizzlejs.com/ -+ * Copyright 2011, The Dojo Foundation -+ * Released under the MIT, BSD, and GPL Licenses. -+ * -+ * Date: Fri Jul 5 14:07:58 UTC 2013 -+ */ -+(function( window, undefined ) { -+ -+// Use the correct document accordingly with window argument (sandbox) -+var document = window.document, -+ navigator = window.navigator, -+ location = window.location; -+var jQuery = (function() { -+ -+// Define a local copy of jQuery -+var jQuery = function( selector, context ) { -+ // The jQuery object is actually just the init constructor 'enhanced' -+ return new jQuery.fn.init( selector, context, rootjQuery ); -+ }, -+ -+ // Map over jQuery in case of overwrite -+ _jQuery = window.jQuery, -+ -+ // Map over the $ in case of overwrite -+ _$ = window.$, -+ -+ // A central reference to the root jQuery(document) -+ rootjQuery, -+ -+ // A simple way to check for HTML strings or ID strings -+ // Prioritize #id over to avoid XSS via location.hash (#9521) -+ quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, -+ -+ // Check if a string has a non-whitespace character in it -+ rnotwhite = /\S/, -+ -+ // Used for trimming whitespace -+ trimLeft = /^\s+/, -+ trimRight = /\s+$/, -+ -+ // Match a standalone tag -+ rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, -+ -+ // JSON RegExp -+ rvalidchars = /^[\],:{}\s]*$/, -+ rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, -+ rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, -+ rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, -+ -+ // Useragent RegExp -+ rwebkit = /(webkit)[ \/]([\w.]+)/, -+ ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, -+ rmsie = /(msie) ([\w.]+)/, -+ rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, -+ -+ // Matches dashed string for camelizing -+ rdashAlpha = /-([a-z]|[0-9])/ig, -+ rmsPrefix = /^-ms-/, -+ -+ // Used by jQuery.camelCase as callback to replace() -+ fcamelCase = function( all, letter ) { -+ return ( letter + "" ).toUpperCase(); -+ }, -+ -+ // Keep a UserAgent string for use with jQuery.browser -+ userAgent = navigator.userAgent, -+ -+ // For matching the engine and version of the browser -+ browserMatch, -+ -+ // The deferred used on DOM ready -+ readyList, -+ -+ // The ready event handler -+ DOMContentLoaded, -+ -+ // Save a reference to some core methods -+ toString = Object.prototype.toString, -+ hasOwn = Object.prototype.hasOwnProperty, -+ push = Array.prototype.push, -+ slice = Array.prototype.slice, -+ trim = String.prototype.trim, -+ indexOf = Array.prototype.indexOf, -+ -+ // [[Class]] -> type pairs -+ class2type = {}; -+ -+jQuery.fn = jQuery.prototype = { -+ constructor: jQuery, -+ init: function( selector, context, rootjQuery ) { -+ var match, elem, ret, doc; -+ -+ // Handle $(""), $(null), or $(undefined) -+ if ( !selector ) { -+ return this; -+ } -+ -+ // Handle $(DOMElement) -+ if ( selector.nodeType ) { -+ this.context = this[0] = selector; -+ this.length = 1; -+ return this; -+ } -+ -+ // The body element only exists once, optimize finding it -+ if ( selector === "body" && !context && document.body ) { -+ this.context = document; -+ this[0] = document.body; -+ this.selector = selector; -+ this.length = 1; -+ return this; -+ } -+ -+ // Handle HTML strings -+ if ( typeof selector === "string" ) { -+ // Are we dealing with HTML string or an ID? -+ if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { -+ // Assume that strings that start and end with <> are HTML and skip the regex check -+ match = [ null, selector, null ]; -+ -+ } else { -+ match = quickExpr.exec( selector ); -+ } -+ -+ // Verify a match, and that no context was specified for #id -+ if ( match && (match[1] || !context) ) { -+ -+ // HANDLE: $(html) -> $(array) -+ if ( match[1] ) { -+ context = context instanceof jQuery ? context[0] : context; -+ doc = ( context ? context.ownerDocument || context : document ); -+ -+ // If a single string is passed in and it's a single tag -+ // just do a createElement and skip the rest -+ ret = rsingleTag.exec( selector ); -+ -+ if ( ret ) { -+ if ( jQuery.isPlainObject( context ) ) { -+ selector = [ document.createElement( ret[1] ) ]; -+ jQuery.fn.attr.call( selector, context, true ); -+ -+ } else { -+ selector = [ doc.createElement( ret[1] ) ]; -+ } -+ -+ } else { -+ ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); -+ selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes; -+ } -+ -+ return jQuery.merge( this, selector ); -+ -+ // HANDLE: $("#id") -+ } else { -+ elem = document.getElementById( match[2] ); -+ -+ // Check parentNode to catch when Blackberry 4.6 returns -+ // nodes that are no longer in the document #6963 -+ if ( elem && elem.parentNode ) { -+ // Handle the case where IE and Opera return items -+ // by name instead of ID -+ if ( elem.id !== match[2] ) { -+ return rootjQuery.find( selector ); -+ } -+ -+ // Otherwise, we inject the element directly into the jQuery object -+ this.length = 1; -+ this[0] = elem; -+ } -+ -+ this.context = document; -+ this.selector = selector; -+ return this; -+ } -+ -+ // HANDLE: $(expr, $(...)) -+ } else if ( !context || context.jquery ) { -+ return ( context || rootjQuery ).find( selector ); -+ -+ // HANDLE: $(expr, context) -+ // (which is just equivalent to: $(context).find(expr) -+ } else { -+ return this.constructor( context ).find( selector ); -+ } -+ -+ // HANDLE: $(function) -+ // Shortcut for document ready -+ } else if ( jQuery.isFunction( selector ) ) { -+ return rootjQuery.ready( selector ); -+ } -+ -+ if ( selector.selector !== undefined ) { -+ this.selector = selector.selector; -+ this.context = selector.context; -+ } -+ -+ return jQuery.makeArray( selector, this ); -+ }, -+ -+ // Start with an empty selector -+ selector: "", -+ -+ // The current version of jQuery being used -+ jquery: "1.7.2", -+ -+ // The default length of a jQuery object is 0 -+ length: 0, -+ -+ // The number of elements contained in the matched element set -+ size: function() { -+ return this.length; -+ }, -+ -+ toArray: function() { -+ return slice.call( this, 0 ); -+ }, -+ -+ // Get the Nth element in the matched element set OR -+ // Get the whole matched element set as a clean array -+ get: function( num ) { -+ return num == null ? -+ -+ // Return a 'clean' array -+ this.toArray() : -+ -+ // Return just the object -+ ( num < 0 ? this[ this.length + num ] : this[ num ] ); -+ }, -+ -+ // Take an array of elements and push it onto the stack -+ // (returning the new matched element set) -+ pushStack: function( elems, name, selector ) { -+ // Build a new jQuery matched element set -+ var ret = this.constructor(); -+ -+ if ( jQuery.isArray( elems ) ) { -+ push.apply( ret, elems ); -+ -+ } else { -+ jQuery.merge( ret, elems ); -+ } -+ -+ // Add the old object onto the stack (as a reference) -+ ret.prevObject = this; -+ -+ ret.context = this.context; -+ -+ if ( name === "find" ) { -+ ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; -+ } else if ( name ) { -+ ret.selector = this.selector + "." + name + "(" + selector + ")"; -+ } -+ -+ // Return the newly-formed element set -+ return ret; -+ }, -+ -+ // Execute a callback for every element in the matched set. -+ // (You can seed the arguments with an array of args, but this is -+ // only used internally.) -+ each: function( callback, args ) { -+ return jQuery.each( this, callback, args ); -+ }, -+ -+ ready: function( fn ) { -+ // Attach the listeners -+ jQuery.bindReady(); -+ -+ // Add the callback -+ readyList.add( fn ); -+ -+ return this; -+ }, -+ -+ eq: function( i ) { -+ i = +i; -+ return i === -1 ? -+ this.slice( i ) : -+ this.slice( i, i + 1 ); -+ }, -+ -+ first: function() { -+ return this.eq( 0 ); -+ }, -+ -+ last: function() { -+ return this.eq( -1 ); -+ }, -+ -+ slice: function() { -+ return this.pushStack( slice.apply( this, arguments ), -+ "slice", slice.call(arguments).join(",") ); -+ }, -+ -+ map: function( callback ) { -+ return this.pushStack( jQuery.map(this, function( elem, i ) { -+ return callback.call( elem, i, elem ); -+ })); -+ }, -+ -+ end: function() { -+ return this.prevObject || this.constructor(null); -+ }, -+ -+ // For internal use only. -+ // Behaves like an Array's method, not like a jQuery method. -+ push: push, -+ sort: [].sort, -+ splice: [].splice -+}; -+ -+// Give the init function the jQuery prototype for later instantiation -+jQuery.fn.init.prototype = jQuery.fn; -+ -+jQuery.extend = jQuery.fn.extend = function() { -+ var options, name, src, copy, copyIsArray, clone, -+ target = arguments[0] || {}, -+ i = 1, -+ length = arguments.length, -+ deep = false; -+ -+ // Handle a deep copy situation -+ if ( typeof target === "boolean" ) { -+ deep = target; -+ target = arguments[1] || {}; -+ // skip the boolean and the target -+ i = 2; -+ } -+ -+ // Handle case when target is a string or something (possible in deep copy) -+ if ( typeof target !== "object" && !jQuery.isFunction(target) ) { -+ target = {}; -+ } -+ -+ // extend jQuery itself if only one argument is passed -+ if ( length === i ) { -+ target = this; -+ --i; -+ } -+ -+ for ( ; i < length; i++ ) { -+ // Only deal with non-null/undefined values -+ if ( (options = arguments[ i ]) != null ) { -+ // Extend the base object -+ for ( name in options ) { -+ src = target[ name ]; -+ copy = options[ name ]; -+ -+ // Prevent never-ending loop -+ if ( target === copy ) { -+ continue; -+ } -+ -+ // Recurse if we're merging plain objects or arrays -+ if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { -+ if ( copyIsArray ) { -+ copyIsArray = false; -+ clone = src && jQuery.isArray(src) ? src : []; -+ -+ } else { -+ clone = src && jQuery.isPlainObject(src) ? src : {}; -+ } -+ -+ // Never move original objects, clone them -+ target[ name ] = jQuery.extend( deep, clone, copy ); -+ -+ // Don't bring in undefined values -+ } else if ( copy !== undefined ) { -+ target[ name ] = copy; -+ } -+ } -+ } -+ } -+ -+ // Return the modified object -+ return target; -+}; -+ -+jQuery.extend({ -+ noConflict: function( deep ) { -+ if ( window.$ === jQuery ) { -+ window.$ = _$; -+ } -+ -+ if ( deep && window.jQuery === jQuery ) { -+ window.jQuery = _jQuery; -+ } -+ -+ return jQuery; -+ }, -+ -+ // Is the DOM ready to be used? Set to true once it occurs. -+ isReady: false, -+ -+ // A counter to track how many items to wait for before -+ // the ready event fires. See #6781 -+ readyWait: 1, -+ -+ // Hold (or release) the ready event -+ holdReady: function( hold ) { -+ if ( hold ) { -+ jQuery.readyWait++; -+ } else { -+ jQuery.ready( true ); -+ } -+ }, -+ -+ // Handle when the DOM is ready -+ ready: function( wait ) { -+ // Either a released hold or an DOMready/load event and not yet ready -+ if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { -+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). -+ if ( !document.body ) { -+ return setTimeout( jQuery.ready, 1 ); -+ } -+ -+ // Remember that the DOM is ready -+ jQuery.isReady = true; -+ -+ // If a normal DOM Ready event fired, decrement, and wait if need be -+ if ( wait !== true && --jQuery.readyWait > 0 ) { -+ return; -+ } -+ -+ // If there are functions bound, to execute -+ readyList.fireWith( document, [ jQuery ] ); -+ -+ // Trigger any bound ready events -+ if ( jQuery.fn.trigger ) { -+ jQuery( document ).trigger( "ready" ).off( "ready" ); -+ } -+ } -+ }, -+ -+ bindReady: function() { -+ if ( readyList ) { -+ return; -+ } -+ -+ readyList = jQuery.Callbacks( "once memory" ); -+ -+ // Catch cases where $(document).ready() is called after the -+ // browser event has already occurred. -+ if ( document.readyState === "complete" ) { -+ // Handle it asynchronously to allow scripts the opportunity to delay ready -+ return setTimeout( jQuery.ready, 1 ); -+ } -+ -+ // Mozilla, Opera and webkit nightlies currently support this event -+ if ( document.addEventListener ) { -+ // Use the handy event callback -+ document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); -+ -+ // A fallback to window.onload, that will always work -+ window.addEventListener( "load", jQuery.ready, false ); -+ -+ // If IE event model is used -+ } else if ( document.attachEvent ) { -+ // ensure firing before onload, -+ // maybe late but safe also for iframes -+ document.attachEvent( "onreadystatechange", DOMContentLoaded ); -+ -+ // A fallback to window.onload, that will always work -+ window.attachEvent( "onload", jQuery.ready ); -+ -+ // If IE and not a frame -+ // continually check to see if the document is ready -+ var toplevel = false; -+ -+ try { -+ toplevel = window.frameElement == null; -+ } catch(e) {} -+ -+ if ( document.documentElement.doScroll && toplevel ) { -+ doScrollCheck(); -+ } -+ } -+ }, -+ -+ // See test/unit/core.js for details concerning isFunction. -+ // Since version 1.3, DOM methods and functions like alert -+ // aren't supported. They return false on IE (#2968). -+ isFunction: function( obj ) { -+ return jQuery.type(obj) === "function"; -+ }, -+ -+ isArray: Array.isArray || function( obj ) { -+ return jQuery.type(obj) === "array"; -+ }, -+ -+ isWindow: function( obj ) { -+ return obj != null && obj == obj.window; -+ }, -+ -+ isNumeric: function( obj ) { -+ return !isNaN( parseFloat(obj) ) && isFinite( obj ); -+ }, -+ -+ type: function( obj ) { -+ return obj == null ? -+ String( obj ) : -+ class2type[ toString.call(obj) ] || "object"; -+ }, -+ -+ isPlainObject: function( obj ) { -+ // Must be an Object. -+ // Because of IE, we also have to check the presence of the constructor property. -+ // Make sure that DOM nodes and window objects don't pass through, as well -+ if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { -+ return false; -+ } -+ -+ try { -+ // Not own constructor property must be Object -+ if ( obj.constructor && -+ !hasOwn.call(obj, "constructor") && -+ !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { -+ return false; -+ } -+ } catch ( e ) { -+ // IE8,9 Will throw exceptions on certain host objects #9897 -+ return false; -+ } -+ -+ // Own properties are enumerated firstly, so to speed up, -+ // if last one is own, then all properties are own. -+ -+ var key; -+ for ( key in obj ) {} -+ -+ return key === undefined || hasOwn.call( obj, key ); -+ }, -+ -+ isEmptyObject: function( obj ) { -+ for ( var name in obj ) { -+ return false; -+ } -+ return true; -+ }, -+ -+ error: function( msg ) { -+ throw new Error( msg ); -+ }, -+ -+ parseJSON: function( data ) { -+ if ( typeof data !== "string" || !data ) { -+ return null; -+ } -+ -+ // Make sure leading/trailing whitespace is removed (IE can't handle it) -+ data = jQuery.trim( data ); -+ -+ // Attempt to parse using the native JSON parser first -+ if ( window.JSON && window.JSON.parse ) { -+ return window.JSON.parse( data ); -+ } -+ -+ // Make sure the incoming data is actual JSON -+ // Logic borrowed from http://json.org/json2.js -+ if ( rvalidchars.test( data.replace( rvalidescape, "@" ) -+ .replace( rvalidtokens, "]" ) -+ .replace( rvalidbraces, "")) ) { -+ -+ return ( new Function( "return " + data ) )(); -+ -+ } -+ jQuery.error( "Invalid JSON: " + data ); -+ }, -+ -+ // Cross-browser xml parsing -+ parseXML: function( data ) { -+ if ( typeof data !== "string" || !data ) { -+ return null; -+ } -+ var xml, tmp; -+ try { -+ if ( window.DOMParser ) { // Standard -+ tmp = new DOMParser(); -+ xml = tmp.parseFromString( data , "text/xml" ); -+ } else { // IE -+ xml = new ActiveXObject( "Microsoft.XMLDOM" ); -+ xml.async = "false"; -+ xml.loadXML( data ); -+ } -+ } catch( e ) { -+ xml = undefined; -+ } -+ if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { -+ jQuery.error( "Invalid XML: " + data ); -+ } -+ return xml; -+ }, -+ -+ noop: function() {}, -+ -+ // Evaluates a script in a global context -+ // Workarounds based on findings by Jim Driscoll -+ // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context -+ globalEval: function( data ) { -+ if ( data && rnotwhite.test( data ) ) { -+ // We use execScript on Internet Explorer -+ // We use an anonymous function so that context is window -+ // rather than jQuery in Firefox -+ ( window.execScript || function( data ) { -+ window[ "eval" ].call( window, data ); -+ } )( data ); -+ } -+ }, -+ -+ // Convert dashed to camelCase; used by the css and data modules -+ // Microsoft forgot to hump their vendor prefix (#9572) -+ camelCase: function( string ) { -+ return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); -+ }, -+ -+ nodeName: function( elem, name ) { -+ return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); -+ }, -+ -+ // args is for internal usage only -+ each: function( object, callback, args ) { -+ var name, i = 0, -+ length = object.length, -+ isObj = length === undefined || jQuery.isFunction( object ); -+ -+ if ( args ) { -+ if ( isObj ) { -+ for ( name in object ) { -+ if ( callback.apply( object[ name ], args ) === false ) { -+ break; -+ } -+ } -+ } else { -+ for ( ; i < length; ) { -+ if ( callback.apply( object[ i++ ], args ) === false ) { -+ break; -+ } -+ } -+ } -+ -+ // A special, fast, case for the most common use of each -+ } else { -+ if ( isObj ) { -+ for ( name in object ) { -+ if ( callback.call( object[ name ], name, object[ name ] ) === false ) { -+ break; -+ } -+ } -+ } else { -+ for ( ; i < length; ) { -+ if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { -+ break; -+ } -+ } -+ } -+ } -+ -+ return object; -+ }, -+ -+ // Use native String.trim function wherever possible -+ trim: trim ? -+ function( text ) { -+ return text == null ? -+ "" : -+ trim.call( text ); -+ } : -+ -+ // Otherwise use our own trimming functionality -+ function( text ) { -+ return text == null ? -+ "" : -+ text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); -+ }, -+ -+ // results is for internal usage only -+ makeArray: function( array, results ) { -+ var ret = results || []; -+ -+ if ( array != null ) { -+ // The window, strings (and functions) also have 'length' -+ // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 -+ var type = jQuery.type( array ); -+ -+ if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { -+ push.call( ret, array ); -+ } else { -+ jQuery.merge( ret, array ); -+ } -+ } -+ -+ return ret; -+ }, -+ -+ inArray: function( elem, array, i ) { -+ var len; -+ -+ if ( array ) { -+ if ( indexOf ) { -+ return indexOf.call( array, elem, i ); -+ } -+ -+ len = array.length; -+ i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; -+ -+ for ( ; i < len; i++ ) { -+ // Skip accessing in sparse arrays -+ if ( i in array && array[ i ] === elem ) { -+ return i; -+ } -+ } -+ } -+ -+ return -1; -+ }, -+ -+ merge: function( first, second ) { -+ var i = first.length, -+ j = 0; -+ -+ if ( typeof second.length === "number" ) { -+ for ( var l = second.length; j < l; j++ ) { -+ first[ i++ ] = second[ j ]; -+ } -+ -+ } else { -+ while ( second[j] !== undefined ) { -+ first[ i++ ] = second[ j++ ]; -+ } -+ } -+ -+ first.length = i; -+ -+ return first; -+ }, -+ -+ grep: function( elems, callback, inv ) { -+ var ret = [], retVal; -+ inv = !!inv; -+ -+ // Go through the array, only saving the items -+ // that pass the validator function -+ for ( var i = 0, length = elems.length; i < length; i++ ) { -+ retVal = !!callback( elems[ i ], i ); -+ if ( inv !== retVal ) { -+ ret.push( elems[ i ] ); -+ } -+ } -+ -+ return ret; -+ }, -+ -+ // arg is for internal usage only -+ map: function( elems, callback, arg ) { -+ var value, key, ret = [], -+ i = 0, -+ length = elems.length, -+ // jquery objects are treated as arrays -+ isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; -+ -+ // Go through the array, translating each of the items to their -+ if ( isArray ) { -+ for ( ; i < length; i++ ) { -+ value = callback( elems[ i ], i, arg ); -+ -+ if ( value != null ) { -+ ret[ ret.length ] = value; -+ } -+ } -+ -+ // Go through every key on the object, -+ } else { -+ for ( key in elems ) { -+ value = callback( elems[ key ], key, arg ); -+ -+ if ( value != null ) { -+ ret[ ret.length ] = value; -+ } -+ } -+ } -+ -+ // Flatten any nested arrays -+ return ret.concat.apply( [], ret ); -+ }, -+ -+ // A global GUID counter for objects -+ guid: 1, -+ -+ // Bind a function to a context, optionally partially applying any -+ // arguments. -+ proxy: function( fn, context ) { -+ if ( typeof context === "string" ) { -+ var tmp = fn[ context ]; -+ context = fn; -+ fn = tmp; -+ } -+ -+ // Quick check to determine if target is callable, in the spec -+ // this throws a TypeError, but we will just return undefined. -+ if ( !jQuery.isFunction( fn ) ) { -+ return undefined; -+ } -+ -+ // Simulated bind -+ var args = slice.call( arguments, 2 ), -+ proxy = function() { -+ return fn.apply( context, args.concat( slice.call( arguments ) ) ); -+ }; -+ -+ // Set the guid of unique handler to the same of original handler, so it can be removed -+ proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; -+ -+ return proxy; -+ }, -+ -+ // Mutifunctional method to get and set values to a collection -+ // The value/s can optionally be executed if it's a function -+ access: function( elems, fn, key, value, chainable, emptyGet, pass ) { -+ var exec, -+ bulk = key == null, -+ i = 0, -+ length = elems.length; -+ -+ // Sets many values -+ if ( key && typeof key === "object" ) { -+ for ( i in key ) { -+ jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); -+ } -+ chainable = 1; -+ -+ // Sets one value -+ } else if ( value !== undefined ) { -+ // Optionally, function values get executed if exec is true -+ exec = pass === undefined && jQuery.isFunction( value ); -+ -+ if ( bulk ) { -+ // Bulk operations only iterate when executing function values -+ if ( exec ) { -+ exec = fn; -+ fn = function( elem, key, value ) { -+ return exec.call( jQuery( elem ), value ); -+ }; -+ -+ // Otherwise they run against the entire set -+ } else { -+ fn.call( elems, value ); -+ fn = null; -+ } -+ } -+ -+ if ( fn ) { -+ for (; i < length; i++ ) { -+ fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); -+ } -+ } -+ -+ chainable = 1; -+ } -+ -+ return chainable ? -+ elems : -+ -+ // Gets -+ bulk ? -+ fn.call( elems ) : -+ length ? fn( elems[0], key ) : emptyGet; -+ }, -+ -+ now: function() { -+ return ( new Date() ).getTime(); -+ }, -+ -+ // Use of jQuery.browser is frowned upon. -+ // More details: http://docs.jquery.com/Utilities/jQuery.browser -+ uaMatch: function( ua ) { -+ ua = ua.toLowerCase(); -+ -+ var match = rwebkit.exec( ua ) || -+ ropera.exec( ua ) || -+ rmsie.exec( ua ) || -+ ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || -+ []; -+ -+ return { browser: match[1] || "", version: match[2] || "0" }; -+ }, -+ -+ sub: function() { -+ function jQuerySub( selector, context ) { -+ return new jQuerySub.fn.init( selector, context ); -+ } -+ jQuery.extend( true, jQuerySub, this ); -+ jQuerySub.superclass = this; -+ jQuerySub.fn = jQuerySub.prototype = this(); -+ jQuerySub.fn.constructor = jQuerySub; -+ jQuerySub.sub = this.sub; -+ jQuerySub.fn.init = function init( selector, context ) { -+ if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { -+ context = jQuerySub( context ); -+ } -+ -+ return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); -+ }; -+ jQuerySub.fn.init.prototype = jQuerySub.fn; -+ var rootjQuerySub = jQuerySub(document); -+ return jQuerySub; -+ }, -+ -+ browser: {} -+}); -+ -+// Populate the class2type map -+jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { -+ class2type[ "[object " + name + "]" ] = name.toLowerCase(); -+}); -+ -+browserMatch = jQuery.uaMatch( userAgent ); -+if ( browserMatch.browser ) { -+ jQuery.browser[ browserMatch.browser ] = true; -+ jQuery.browser.version = browserMatch.version; -+} -+ -+// Deprecated, use jQuery.browser.webkit instead -+if ( jQuery.browser.webkit ) { -+ jQuery.browser.safari = true; -+} -+ -+// IE doesn't match non-breaking spaces with \s -+if ( rnotwhite.test( "\xA0" ) ) { -+ trimLeft = /^[\s\xA0]+/; -+ trimRight = /[\s\xA0]+$/; -+} -+ -+// All jQuery objects should point back to these -+rootjQuery = jQuery(document); -+ -+// Cleanup functions for the document ready method -+if ( document.addEventListener ) { -+ DOMContentLoaded = function() { -+ document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); -+ jQuery.ready(); -+ }; -+ -+} else if ( document.attachEvent ) { -+ DOMContentLoaded = function() { -+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). -+ if ( document.readyState === "complete" ) { -+ document.detachEvent( "onreadystatechange", DOMContentLoaded ); -+ jQuery.ready(); -+ } -+ }; -+} -+ -+// The DOM ready check for Internet Explorer -+function doScrollCheck() { -+ if ( jQuery.isReady ) { -+ return; -+ } -+ -+ try { -+ // If IE is used, use the trick by Diego Perini -+ // http://javascript.nwbox.com/IEContentLoaded/ -+ document.documentElement.doScroll("left"); -+ } catch(e) { -+ setTimeout( doScrollCheck, 1 ); -+ return; -+ } -+ -+ // and execute any waiting functions -+ jQuery.ready(); -+} -+ -+return jQuery; -+ -+})(); -+ -+ -+// String to Object flags format cache -+var flagsCache = {}; -+ -+// Convert String-formatted flags into Object-formatted ones and store in cache -+function createFlags( flags ) { -+ var object = flagsCache[ flags ] = {}, -+ i, length; -+ flags = flags.split( /\s+/ ); -+ for ( i = 0, length = flags.length; i < length; i++ ) { -+ object[ flags[i] ] = true; -+ } -+ return object; -+} -+ -+/* -+ * Create a callback list using the following parameters: -+ * -+ * flags: an optional list of space-separated flags that will change how -+ * the callback list behaves -+ * -+ * By default a callback list will act like an event callback list and can be -+ * "fired" multiple times. -+ * -+ * Possible flags: -+ * -+ * once: will ensure the callback list can only be fired once (like a Deferred) -+ * -+ * memory: will keep track of previous values and will call any callback added -+ * after the list has been fired right away with the latest "memorized" -+ * values (like a Deferred) -+ * -+ * unique: will ensure a callback can only be added once (no duplicate in the list) -+ * -+ * stopOnFalse: interrupt callings when a callback returns false -+ * -+ */ -+jQuery.Callbacks = function( flags ) { -+ -+ // Convert flags from String-formatted to Object-formatted -+ // (we check in cache first) -+ flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {}; -+ -+ var // Actual callback list -+ list = [], -+ // Stack of fire calls for repeatable lists -+ stack = [], -+ // Last fire value (for non-forgettable lists) -+ memory, -+ // Flag to know if list was already fired -+ fired, -+ // Flag to know if list is currently firing -+ firing, -+ // First callback to fire (used internally by add and fireWith) -+ firingStart, -+ // End of the loop when firing -+ firingLength, -+ // Index of currently firing callback (modified by remove if needed) -+ firingIndex, -+ // Add one or several callbacks to the list -+ add = function( args ) { -+ var i, -+ length, -+ elem, -+ type, -+ actual; -+ for ( i = 0, length = args.length; i < length; i++ ) { -+ elem = args[ i ]; -+ type = jQuery.type( elem ); -+ if ( type === "array" ) { -+ // Inspect recursively -+ add( elem ); -+ } else if ( type === "function" ) { -+ // Add if not in unique mode and callback is not in -+ if ( !flags.unique || !self.has( elem ) ) { -+ list.push( elem ); -+ } -+ } -+ } -+ }, -+ // Fire callbacks -+ fire = function( context, args ) { -+ args = args || []; -+ memory = !flags.memory || [ context, args ]; -+ fired = true; -+ firing = true; -+ firingIndex = firingStart || 0; -+ firingStart = 0; -+ firingLength = list.length; -+ for ( ; list && firingIndex < firingLength; firingIndex++ ) { -+ if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) { -+ memory = true; // Mark as halted -+ break; -+ } -+ } -+ firing = false; -+ if ( list ) { -+ if ( !flags.once ) { -+ if ( stack && stack.length ) { -+ memory = stack.shift(); -+ self.fireWith( memory[ 0 ], memory[ 1 ] ); -+ } -+ } else if ( memory === true ) { -+ self.disable(); -+ } else { -+ list = []; -+ } -+ } -+ }, -+ // Actual Callbacks object -+ self = { -+ // Add a callback or a collection of callbacks to the list -+ add: function() { -+ if ( list ) { -+ var length = list.length; -+ add( arguments ); -+ // Do we need to add the callbacks to the -+ // current firing batch? -+ if ( firing ) { -+ firingLength = list.length; -+ // With memory, if we're not firing then -+ // we should call right away, unless previous -+ // firing was halted (stopOnFalse) -+ } else if ( memory && memory !== true ) { -+ firingStart = length; -+ fire( memory[ 0 ], memory[ 1 ] ); -+ } -+ } -+ return this; -+ }, -+ // Remove a callback from the list -+ remove: function() { -+ if ( list ) { -+ var args = arguments, -+ argIndex = 0, -+ argLength = args.length; -+ for ( ; argIndex < argLength ; argIndex++ ) { -+ for ( var i = 0; i < list.length; i++ ) { -+ if ( args[ argIndex ] === list[ i ] ) { -+ // Handle firingIndex and firingLength -+ if ( firing ) { -+ if ( i <= firingLength ) { -+ firingLength--; -+ if ( i <= firingIndex ) { -+ firingIndex--; -+ } -+ } -+ } -+ // Remove the element -+ list.splice( i--, 1 ); -+ // If we have some unicity property then -+ // we only need to do this once -+ if ( flags.unique ) { -+ break; -+ } -+ } -+ } -+ } -+ } -+ return this; -+ }, -+ // Control if a given callback is in the list -+ has: function( fn ) { -+ if ( list ) { -+ var i = 0, -+ length = list.length; -+ for ( ; i < length; i++ ) { -+ if ( fn === list[ i ] ) { -+ return true; -+ } -+ } -+ } -+ return false; -+ }, -+ // Remove all callbacks from the list -+ empty: function() { -+ list = []; -+ return this; -+ }, -+ // Have the list do nothing anymore -+ disable: function() { -+ list = stack = memory = undefined; -+ return this; -+ }, -+ // Is it disabled? -+ disabled: function() { -+ return !list; -+ }, -+ // Lock the list in its current state -+ lock: function() { -+ stack = undefined; -+ if ( !memory || memory === true ) { -+ self.disable(); -+ } -+ return this; -+ }, -+ // Is it locked? -+ locked: function() { -+ return !stack; -+ }, -+ // Call all callbacks with the given context and arguments -+ fireWith: function( context, args ) { -+ if ( stack ) { -+ if ( firing ) { -+ if ( !flags.once ) { -+ stack.push( [ context, args ] ); -+ } -+ } else if ( !( flags.once && memory ) ) { -+ fire( context, args ); -+ } -+ } -+ return this; -+ }, -+ // Call all the callbacks with the given arguments -+ fire: function() { -+ self.fireWith( this, arguments ); -+ return this; -+ }, -+ // To know if the callbacks have already been called at least once -+ fired: function() { -+ return !!fired; -+ } -+ }; -+ -+ return self; -+}; -+ -+ -+ -+ -+var // Static reference to slice -+ sliceDeferred = [].slice; -+ -+jQuery.extend({ -+ -+ Deferred: function( func ) { -+ var doneList = jQuery.Callbacks( "once memory" ), -+ failList = jQuery.Callbacks( "once memory" ), -+ progressList = jQuery.Callbacks( "memory" ), -+ state = "pending", -+ lists = { -+ resolve: doneList, -+ reject: failList, -+ notify: progressList -+ }, -+ promise = { -+ done: doneList.add, -+ fail: failList.add, -+ progress: progressList.add, -+ -+ state: function() { -+ return state; -+ }, -+ -+ // Deprecated -+ isResolved: doneList.fired, -+ isRejected: failList.fired, -+ -+ then: function( doneCallbacks, failCallbacks, progressCallbacks ) { -+ deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks ); -+ return this; -+ }, -+ always: function() { -+ deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments ); -+ return this; -+ }, -+ pipe: function( fnDone, fnFail, fnProgress ) { -+ return jQuery.Deferred(function( newDefer ) { -+ jQuery.each( { -+ done: [ fnDone, "resolve" ], -+ fail: [ fnFail, "reject" ], -+ progress: [ fnProgress, "notify" ] -+ }, function( handler, data ) { -+ var fn = data[ 0 ], -+ action = data[ 1 ], -+ returned; -+ if ( jQuery.isFunction( fn ) ) { -+ deferred[ handler ](function() { -+ returned = fn.apply( this, arguments ); -+ if ( returned && jQuery.isFunction( returned.promise ) ) { -+ returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify ); -+ } else { -+ newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); -+ } -+ }); -+ } else { -+ deferred[ handler ]( newDefer[ action ] ); -+ } -+ }); -+ }).promise(); -+ }, -+ // Get a promise for this deferred -+ // If obj is provided, the promise aspect is added to the object -+ promise: function( obj ) { -+ if ( obj == null ) { -+ obj = promise; -+ } else { -+ for ( var key in promise ) { -+ obj[ key ] = promise[ key ]; -+ } -+ } -+ return obj; -+ } -+ }, -+ deferred = promise.promise({}), -+ key; -+ -+ for ( key in lists ) { -+ deferred[ key ] = lists[ key ].fire; -+ deferred[ key + "With" ] = lists[ key ].fireWith; -+ } -+ -+ // Handle state -+ deferred.done( function() { -+ state = "resolved"; -+ }, failList.disable, progressList.lock ).fail( function() { -+ state = "rejected"; -+ }, doneList.disable, progressList.lock ); -+ -+ // Call given func if any -+ if ( func ) { -+ func.call( deferred, deferred ); -+ } -+ -+ // All done! -+ return deferred; -+ }, -+ -+ // Deferred helper -+ when: function( firstParam ) { -+ var args = sliceDeferred.call( arguments, 0 ), -+ i = 0, -+ length = args.length, -+ pValues = new Array( length ), -+ count = length, -+ pCount = length, -+ deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? -+ firstParam : -+ jQuery.Deferred(), -+ promise = deferred.promise(); -+ function resolveFunc( i ) { -+ return function( value ) { -+ args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; -+ if ( !( --count ) ) { -+ deferred.resolveWith( deferred, args ); -+ } -+ }; -+ } -+ function progressFunc( i ) { -+ return function( value ) { -+ pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; -+ deferred.notifyWith( promise, pValues ); -+ }; -+ } -+ if ( length > 1 ) { -+ for ( ; i < length; i++ ) { -+ if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) { -+ args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) ); -+ } else { -+ --count; -+ } -+ } -+ if ( !count ) { -+ deferred.resolveWith( deferred, args ); -+ } -+ } else if ( deferred !== firstParam ) { -+ deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); -+ } -+ return promise; -+ } -+}); -+ -+ -+ -+ -+jQuery.support = (function() { -+ -+ var support, -+ all, -+ a, -+ select, -+ opt, -+ input, -+ fragment, -+ tds, -+ events, -+ eventName, -+ i, -+ isSupported, -+ div = document.createElement( "div" ), -+ documentElement = document.documentElement; -+ -+ // Preliminary tests -+ div.setAttribute("className", "t"); -+ div.innerHTML = "
a"; -+ -+ all = div.getElementsByTagName( "*" ); -+ a = div.getElementsByTagName( "a" )[ 0 ]; -+ -+ // Can't get basic test support -+ if ( !all || !all.length || !a ) { -+ return {}; -+ } -+ -+ // First batch of supports tests -+ select = document.createElement( "select" ); -+ opt = select.appendChild( document.createElement("option") ); -+ input = div.getElementsByTagName( "input" )[ 0 ]; -+ -+ support = { -+ // IE strips leading whitespace when .innerHTML is used -+ leadingWhitespace: ( div.firstChild.nodeType === 3 ), -+ -+ // Make sure that tbody elements aren't automatically inserted -+ // IE will insert them into empty tables -+ tbody: !div.getElementsByTagName("tbody").length, -+ -+ // Make sure that link elements get serialized correctly by innerHTML -+ // This requires a wrapper element in IE -+ htmlSerialize: !!div.getElementsByTagName("link").length, -+ -+ // Get the style information from getAttribute -+ // (IE uses .cssText instead) -+ style: /top/.test( a.getAttribute("style") ), -+ -+ // Make sure that URLs aren't manipulated -+ // (IE normalizes it by default) -+ hrefNormalized: ( a.getAttribute("href") === "/a" ), -+ -+ // Make sure that element opacity exists -+ // (IE uses filter instead) -+ // Use a regex to work around a WebKit issue. See #5145 -+ opacity: /^0.55/.test( a.style.opacity ), -+ -+ // Verify style float existence -+ // (IE uses styleFloat instead of cssFloat) -+ cssFloat: !!a.style.cssFloat, -+ -+ // Make sure that if no value is specified for a checkbox -+ // that it defaults to "on". -+ // (WebKit defaults to "" instead) -+ checkOn: ( input.value === "on" ), -+ -+ // Make sure that a selected-by-default option has a working selected property. -+ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) -+ optSelected: opt.selected, -+ -+ // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) -+ getSetAttribute: div.className !== "t", -+ -+ // Tests for enctype support on a form(#6743) -+ enctype: !!document.createElement("form").enctype, -+ -+ // Makes sure cloning an html5 element does not cause problems -+ // Where outerHTML is undefined, this still works -+ html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", -+ -+ // Will be defined later -+ submitBubbles: true, -+ changeBubbles: true, -+ focusinBubbles: false, -+ deleteExpando: true, -+ noCloneEvent: true, -+ inlineBlockNeedsLayout: false, -+ shrinkWrapBlocks: false, -+ reliableMarginRight: true, -+ pixelMargin: true -+ }; -+ -+ // jQuery.boxModel DEPRECATED in 1.3, use jQuery.support.boxModel instead -+ jQuery.boxModel = support.boxModel = (document.compatMode === "CSS1Compat"); -+ -+ // Make sure checked status is properly cloned -+ input.checked = true; -+ support.noCloneChecked = input.cloneNode( true ).checked; -+ -+ // Make sure that the options inside disabled selects aren't marked as disabled -+ // (WebKit marks them as disabled) -+ select.disabled = true; -+ support.optDisabled = !opt.disabled; -+ -+ // Test to see if it's possible to delete an expando from an element -+ // Fails in Internet Explorer -+ try { -+ delete div.test; -+ } catch( e ) { -+ support.deleteExpando = false; -+ } -+ -+ if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { -+ div.attachEvent( "onclick", function() { -+ // Cloning a node shouldn't copy over any -+ // bound event handlers (IE does this) -+ support.noCloneEvent = false; -+ }); -+ div.cloneNode( true ).fireEvent( "onclick" ); -+ } -+ -+ // Check if a radio maintains its value -+ // after being appended to the DOM -+ input = document.createElement("input"); -+ input.value = "t"; -+ input.setAttribute("type", "radio"); -+ support.radioValue = input.value === "t"; -+ -+ input.setAttribute("checked", "checked"); -+ -+ // #11217 - WebKit loses check when the name is after the checked attribute -+ input.setAttribute( "name", "t" ); -+ -+ div.appendChild( input ); -+ fragment = document.createDocumentFragment(); -+ fragment.appendChild( div.lastChild ); -+ -+ // WebKit doesn't clone checked state correctly in fragments -+ support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; -+ -+ // Check if a disconnected checkbox will retain its checked -+ // value of true after appended to the DOM (IE6/7) -+ support.appendChecked = input.checked; -+ -+ fragment.removeChild( input ); -+ fragment.appendChild( div ); -+ -+ // Technique from Juriy Zaytsev -+ // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ -+ // We only care about the case where non-standard event systems -+ // are used, namely in IE. Short-circuiting here helps us to -+ // avoid an eval call (in setAttribute) which can cause CSP -+ // to go haywire. See: https://developer.mozilla.org/en/Security/CSP -+ if ( div.attachEvent ) { -+ for ( i in { -+ submit: 1, -+ change: 1, -+ focusin: 1 -+ }) { -+ eventName = "on" + i; -+ isSupported = ( eventName in div ); -+ if ( !isSupported ) { -+ div.setAttribute( eventName, "return;" ); -+ isSupported = ( typeof div[ eventName ] === "function" ); -+ } -+ support[ i + "Bubbles" ] = isSupported; -+ } -+ } -+ -+ fragment.removeChild( div ); -+ -+ // Null elements to avoid leaks in IE -+ fragment = select = opt = div = input = null; -+ -+ // Run tests that need a body at doc ready -+ jQuery(function() { -+ var container, outer, inner, table, td, offsetSupport, -+ marginDiv, conMarginTop, style, html, positionTopLeftWidthHeight, -+ paddingMarginBorderVisibility, paddingMarginBorder, -+ body = document.getElementsByTagName("body")[0]; -+ -+ if ( !body ) { -+ // Return for frameset docs that don't have a body -+ return; -+ } -+ -+ conMarginTop = 1; -+ paddingMarginBorder = "padding:0;margin:0;border:"; -+ positionTopLeftWidthHeight = "position:absolute;top:0;left:0;width:1px;height:1px;"; -+ paddingMarginBorderVisibility = paddingMarginBorder + "0;visibility:hidden;"; -+ style = "style='" + positionTopLeftWidthHeight + paddingMarginBorder + "5px solid #000;"; -+ html = "
" + -+ "" + -+ "
"; -+ -+ container = document.createElement("div"); -+ container.style.cssText = paddingMarginBorderVisibility + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px"; -+ body.insertBefore( container, body.firstChild ); -+ -+ // Construct the test element -+ div = document.createElement("div"); -+ container.appendChild( div ); -+ -+ // Check if table cells still have offsetWidth/Height when they are set -+ // to display:none and there are still other visible table cells in a -+ // table row; if so, offsetWidth/Height are not reliable for use when -+ // determining if an element has been hidden directly using -+ // display:none (it is still safe to use offsets if a parent element is -+ // hidden; don safety goggles and see bug #4512 for more information). -+ // (only IE 8 fails this test) -+ div.innerHTML = "
t
"; -+ tds = div.getElementsByTagName( "td" ); -+ isSupported = ( tds[ 0 ].offsetHeight === 0 ); -+ -+ tds[ 0 ].style.display = ""; -+ tds[ 1 ].style.display = "none"; -+ -+ // Check if empty table cells still have offsetWidth/Height -+ // (IE <= 8 fail this test) -+ support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); -+ -+ // Check if div with explicit width and no margin-right incorrectly -+ // gets computed margin-right based on width of container. For more -+ // info see bug #3333 -+ // Fails in WebKit before Feb 2011 nightlies -+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right -+ if ( window.getComputedStyle ) { -+ div.innerHTML = ""; -+ marginDiv = document.createElement( "div" ); -+ marginDiv.style.width = "0"; -+ marginDiv.style.marginRight = "0"; -+ div.style.width = "2px"; -+ div.appendChild( marginDiv ); -+ support.reliableMarginRight = -+ ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; -+ } -+ -+ if ( typeof div.style.zoom !== "undefined" ) { -+ // Check if natively block-level elements act like inline-block -+ // elements when setting their display to 'inline' and giving -+ // them layout -+ // (IE < 8 does this) -+ div.innerHTML = ""; -+ div.style.width = div.style.padding = "1px"; -+ div.style.border = 0; -+ div.style.overflow = "hidden"; -+ div.style.display = "inline"; -+ div.style.zoom = 1; -+ support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); -+ -+ // Check if elements with layout shrink-wrap their children -+ // (IE 6 does this) -+ div.style.display = "block"; -+ div.style.overflow = "visible"; -+ div.innerHTML = "
"; -+ support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); -+ } -+ -+ div.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility; -+ div.innerHTML = html; -+ -+ outer = div.firstChild; -+ inner = outer.firstChild; -+ td = outer.nextSibling.firstChild.firstChild; -+ -+ offsetSupport = { -+ doesNotAddBorder: ( inner.offsetTop !== 5 ), -+ doesAddBorderForTableAndCells: ( td.offsetTop === 5 ) -+ }; -+ -+ inner.style.position = "fixed"; -+ inner.style.top = "20px"; -+ -+ // safari subtracts parent border width here which is 5px -+ offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 ); -+ inner.style.position = inner.style.top = ""; -+ -+ outer.style.overflow = "hidden"; -+ outer.style.position = "relative"; -+ -+ offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 ); -+ offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop ); -+ -+ if ( window.getComputedStyle ) { -+ div.style.marginTop = "1%"; -+ support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%"; -+ } -+ -+ if ( typeof container.style.zoom !== "undefined" ) { -+ container.style.zoom = 1; -+ } -+ -+ body.removeChild( container ); -+ marginDiv = div = container = null; -+ -+ jQuery.extend( support, offsetSupport ); -+ }); -+ -+ return support; -+})(); -+ -+ -+ -+ -+var rbrace = /^(?:\{.*\}|\[.*\])$/, -+ rmultiDash = /([A-Z])/g; -+ -+jQuery.extend({ -+ cache: {}, -+ -+ // Please use with caution -+ uuid: 0, -+ -+ // Unique for each copy of jQuery on the page -+ // Non-digits removed to match rinlinejQuery -+ expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), -+ -+ // The following elements throw uncatchable exceptions if you -+ // attempt to add expando properties to them. -+ noData: { -+ "embed": true, -+ // Ban all objects except for Flash (which handle expandos) -+ "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", -+ "applet": true -+ }, -+ -+ hasData: function( elem ) { -+ elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; -+ return !!elem && !isEmptyDataObject( elem ); -+ }, -+ -+ data: function( elem, name, data, pvt /* Internal Use Only */ ) { -+ if ( !jQuery.acceptData( elem ) ) { -+ return; -+ } -+ -+ var privateCache, thisCache, ret, -+ internalKey = jQuery.expando, -+ getByName = typeof name === "string", -+ -+ // We have to handle DOM nodes and JS objects differently because IE6-7 -+ // can't GC object references properly across the DOM-JS boundary -+ isNode = elem.nodeType, -+ -+ // Only DOM nodes need the global jQuery cache; JS object data is -+ // attached directly to the object so GC can occur automatically -+ cache = isNode ? jQuery.cache : elem, -+ -+ // Only defining an ID for JS objects if its cache already exists allows -+ // the code to shortcut on the same path as a DOM node with no cache -+ id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey, -+ isEvents = name === "events"; -+ -+ // Avoid doing any more work than we need to when trying to get data on an -+ // object that has no data at all -+ if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) { -+ return; -+ } -+ -+ if ( !id ) { -+ // Only DOM nodes need a new unique ID for each element since their data -+ // ends up in the global cache -+ if ( isNode ) { -+ elem[ internalKey ] = id = ++jQuery.uuid; -+ } else { -+ id = internalKey; -+ } -+ } -+ -+ if ( !cache[ id ] ) { -+ cache[ id ] = {}; -+ -+ // Avoids exposing jQuery metadata on plain JS objects when the object -+ // is serialized using JSON.stringify -+ if ( !isNode ) { -+ cache[ id ].toJSON = jQuery.noop; -+ } -+ } -+ -+ // An object can be passed to jQuery.data instead of a key/value pair; this gets -+ // shallow copied over onto the existing cache -+ if ( typeof name === "object" || typeof name === "function" ) { -+ if ( pvt ) { -+ cache[ id ] = jQuery.extend( cache[ id ], name ); -+ } else { -+ cache[ id ].data = jQuery.extend( cache[ id ].data, name ); -+ } -+ } -+ -+ privateCache = thisCache = cache[ id ]; -+ -+ // jQuery data() is stored in a separate object inside the object's internal data -+ // cache in order to avoid key collisions between internal data and user-defined -+ // data. -+ if ( !pvt ) { -+ if ( !thisCache.data ) { -+ thisCache.data = {}; -+ } -+ -+ thisCache = thisCache.data; -+ } -+ -+ if ( data !== undefined ) { -+ thisCache[ jQuery.camelCase( name ) ] = data; -+ } -+ -+ // Users should not attempt to inspect the internal events object using jQuery.data, -+ // it is undocumented and subject to change. But does anyone listen? No. -+ if ( isEvents && !thisCache[ name ] ) { -+ return privateCache.events; -+ } -+ -+ // Check for both converted-to-camel and non-converted data property names -+ // If a data property was specified -+ if ( getByName ) { -+ -+ // First Try to find as-is property data -+ ret = thisCache[ name ]; -+ -+ // Test for null|undefined property data -+ if ( ret == null ) { -+ -+ // Try to find the camelCased property -+ ret = thisCache[ jQuery.camelCase( name ) ]; -+ } -+ } else { -+ ret = thisCache; -+ } -+ -+ return ret; -+ }, -+ -+ removeData: function( elem, name, pvt /* Internal Use Only */ ) { -+ if ( !jQuery.acceptData( elem ) ) { -+ return; -+ } -+ -+ var thisCache, i, l, -+ -+ // Reference to internal data cache key -+ internalKey = jQuery.expando, -+ -+ isNode = elem.nodeType, -+ -+ // See jQuery.data for more information -+ cache = isNode ? jQuery.cache : elem, -+ -+ // See jQuery.data for more information -+ id = isNode ? elem[ internalKey ] : internalKey; -+ -+ // If there is already no cache entry for this object, there is no -+ // purpose in continuing -+ if ( !cache[ id ] ) { -+ return; -+ } -+ -+ if ( name ) { -+ -+ thisCache = pvt ? cache[ id ] : cache[ id ].data; -+ -+ if ( thisCache ) { -+ -+ // Support array or space separated string names for data keys -+ if ( !jQuery.isArray( name ) ) { -+ -+ // try the string as a key before any manipulation -+ if ( name in thisCache ) { -+ name = [ name ]; -+ } else { -+ -+ // split the camel cased version by spaces unless a key with the spaces exists -+ name = jQuery.camelCase( name ); -+ if ( name in thisCache ) { -+ name = [ name ]; -+ } else { -+ name = name.split( " " ); -+ } -+ } -+ } -+ -+ for ( i = 0, l = name.length; i < l; i++ ) { -+ delete thisCache[ name[i] ]; -+ } -+ -+ // If there is no data left in the cache, we want to continue -+ // and let the cache object itself get destroyed -+ if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { -+ return; -+ } -+ } -+ } -+ -+ // See jQuery.data for more information -+ if ( !pvt ) { -+ delete cache[ id ].data; -+ -+ // Don't destroy the parent cache unless the internal data object -+ // had been the only thing left in it -+ if ( !isEmptyDataObject(cache[ id ]) ) { -+ return; -+ } -+ } -+ -+ // Browsers that fail expando deletion also refuse to delete expandos on -+ // the window, but it will allow it on all other JS objects; other browsers -+ // don't care -+ // Ensure that `cache` is not a window object #10080 -+ if ( jQuery.support.deleteExpando || !cache.setInterval ) { -+ delete cache[ id ]; -+ } else { -+ cache[ id ] = null; -+ } -+ -+ // We destroyed the cache and need to eliminate the expando on the node to avoid -+ // false lookups in the cache for entries that no longer exist -+ if ( isNode ) { -+ // IE does not allow us to delete expando properties from nodes, -+ // nor does it have a removeAttribute function on Document nodes; -+ // we must handle all of these cases -+ if ( jQuery.support.deleteExpando ) { -+ delete elem[ internalKey ]; -+ } else if ( elem.removeAttribute ) { -+ elem.removeAttribute( internalKey ); -+ } else { -+ elem[ internalKey ] = null; -+ } -+ } -+ }, -+ -+ // For internal use only. -+ _data: function( elem, name, data ) { -+ return jQuery.data( elem, name, data, true ); -+ }, -+ -+ // A method for determining if a DOM node can handle the data expando -+ acceptData: function( elem ) { -+ if ( elem.nodeName ) { -+ var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; -+ -+ if ( match ) { -+ return !(match === true || elem.getAttribute("classid") !== match); -+ } -+ } -+ -+ return true; -+ } -+}); -+ -+jQuery.fn.extend({ -+ data: function( key, value ) { -+ var parts, part, attr, name, l, -+ elem = this[0], -+ i = 0, -+ data = null; -+ -+ // Gets all values -+ if ( key === undefined ) { -+ if ( this.length ) { -+ data = jQuery.data( elem ); -+ -+ if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { -+ attr = elem.attributes; -+ for ( l = attr.length; i < l; i++ ) { -+ name = attr[i].name; -+ -+ if ( name.indexOf( "data-" ) === 0 ) { -+ name = jQuery.camelCase( name.substring(5) ); -+ -+ dataAttr( elem, name, data[ name ] ); -+ } -+ } -+ jQuery._data( elem, "parsedAttrs", true ); -+ } -+ } -+ -+ return data; -+ } -+ -+ // Sets multiple values -+ if ( typeof key === "object" ) { -+ return this.each(function() { -+ jQuery.data( this, key ); -+ }); -+ } -+ -+ parts = key.split( ".", 2 ); -+ parts[1] = parts[1] ? "." + parts[1] : ""; -+ part = parts[1] + "!"; -+ -+ return jQuery.access( this, function( value ) { -+ -+ if ( value === undefined ) { -+ data = this.triggerHandler( "getData" + part, [ parts[0] ] ); -+ -+ // Try to fetch any internally stored data first -+ if ( data === undefined && elem ) { -+ data = jQuery.data( elem, key ); -+ data = dataAttr( elem, key, data ); -+ } -+ -+ return data === undefined && parts[1] ? -+ this.data( parts[0] ) : -+ data; -+ } -+ -+ parts[1] = value; -+ this.each(function() { -+ var self = jQuery( this ); -+ -+ self.triggerHandler( "setData" + part, parts ); -+ jQuery.data( this, key, value ); -+ self.triggerHandler( "changeData" + part, parts ); -+ }); -+ }, null, value, arguments.length > 1, null, false ); -+ }, -+ -+ removeData: function( key ) { -+ return this.each(function() { -+ jQuery.removeData( this, key ); -+ }); -+ } -+}); -+ -+function dataAttr( elem, key, data ) { -+ // If nothing was found internally, try to fetch any -+ // data from the HTML5 data-* attribute -+ if ( data === undefined && elem.nodeType === 1 ) { -+ -+ var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); -+ -+ data = elem.getAttribute( name ); -+ -+ if ( typeof data === "string" ) { -+ try { -+ data = data === "true" ? true : -+ data === "false" ? false : -+ data === "null" ? null : -+ jQuery.isNumeric( data ) ? +data : -+ rbrace.test( data ) ? jQuery.parseJSON( data ) : -+ data; -+ } catch( e ) {} -+ -+ // Make sure we set the data so it isn't changed later -+ jQuery.data( elem, key, data ); -+ -+ } else { -+ data = undefined; -+ } -+ } -+ -+ return data; -+} -+ -+// checks a cache object for emptiness -+function isEmptyDataObject( obj ) { -+ for ( var name in obj ) { -+ -+ // if the public data object is empty, the private is still empty -+ if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { -+ continue; -+ } -+ if ( name !== "toJSON" ) { -+ return false; -+ } -+ } -+ -+ return true; -+} -+ -+ -+ -+ -+function handleQueueMarkDefer( elem, type, src ) { -+ var deferDataKey = type + "defer", -+ queueDataKey = type + "queue", -+ markDataKey = type + "mark", -+ defer = jQuery._data( elem, deferDataKey ); -+ if ( defer && -+ ( src === "queue" || !jQuery._data(elem, queueDataKey) ) && -+ ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) { -+ // Give room for hard-coded callbacks to fire first -+ // and eventually mark/queue something else on the element -+ setTimeout( function() { -+ if ( !jQuery._data( elem, queueDataKey ) && -+ !jQuery._data( elem, markDataKey ) ) { -+ jQuery.removeData( elem, deferDataKey, true ); -+ defer.fire(); -+ } -+ }, 0 ); -+ } -+} -+ -+jQuery.extend({ -+ -+ _mark: function( elem, type ) { -+ if ( elem ) { -+ type = ( type || "fx" ) + "mark"; -+ jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 ); -+ } -+ }, -+ -+ _unmark: function( force, elem, type ) { -+ if ( force !== true ) { -+ type = elem; -+ elem = force; -+ force = false; -+ } -+ if ( elem ) { -+ type = type || "fx"; -+ var key = type + "mark", -+ count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 ); -+ if ( count ) { -+ jQuery._data( elem, key, count ); -+ } else { -+ jQuery.removeData( elem, key, true ); -+ handleQueueMarkDefer( elem, type, "mark" ); -+ } -+ } -+ }, -+ -+ queue: function( elem, type, data ) { -+ var q; -+ if ( elem ) { -+ type = ( type || "fx" ) + "queue"; -+ q = jQuery._data( elem, type ); -+ -+ // Speed up dequeue by getting out quickly if this is just a lookup -+ if ( data ) { -+ if ( !q || jQuery.isArray(data) ) { -+ q = jQuery._data( elem, type, jQuery.makeArray(data) ); -+ } else { -+ q.push( data ); -+ } -+ } -+ return q || []; -+ } -+ }, -+ -+ dequeue: function( elem, type ) { -+ type = type || "fx"; -+ -+ var queue = jQuery.queue( elem, type ), -+ fn = queue.shift(), -+ hooks = {}; -+ -+ // If the fx queue is dequeued, always remove the progress sentinel -+ if ( fn === "inprogress" ) { -+ fn = queue.shift(); -+ } -+ -+ if ( fn ) { -+ // Add a progress sentinel to prevent the fx queue from being -+ // automatically dequeued -+ if ( type === "fx" ) { -+ queue.unshift( "inprogress" ); -+ } -+ -+ jQuery._data( elem, type + ".run", hooks ); -+ fn.call( elem, function() { -+ jQuery.dequeue( elem, type ); -+ }, hooks ); -+ } -+ -+ if ( !queue.length ) { -+ jQuery.removeData( elem, type + "queue " + type + ".run", true ); -+ handleQueueMarkDefer( elem, type, "queue" ); -+ } -+ } -+}); -+ -+jQuery.fn.extend({ -+ queue: function( type, data ) { -+ var setter = 2; -+ -+ if ( typeof type !== "string" ) { -+ data = type; -+ type = "fx"; -+ setter--; -+ } -+ -+ if ( arguments.length < setter ) { -+ return jQuery.queue( this[0], type ); -+ } -+ -+ return data === undefined ? -+ this : -+ this.each(function() { -+ var queue = jQuery.queue( this, type, data ); -+ -+ if ( type === "fx" && queue[0] !== "inprogress" ) { -+ jQuery.dequeue( this, type ); -+ } -+ }); -+ }, -+ dequeue: function( type ) { -+ return this.each(function() { -+ jQuery.dequeue( this, type ); -+ }); -+ }, -+ // Based off of the plugin by Clint Helfers, with permission. -+ // http://blindsignals.com/index.php/2009/07/jquery-delay/ -+ delay: function( time, type ) { -+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; -+ type = type || "fx"; -+ -+ return this.queue( type, function( next, hooks ) { -+ var timeout = setTimeout( next, time ); -+ hooks.stop = function() { -+ clearTimeout( timeout ); -+ }; -+ }); -+ }, -+ clearQueue: function( type ) { -+ return this.queue( type || "fx", [] ); -+ }, -+ // Get a promise resolved when queues of a certain type -+ // are emptied (fx is the type by default) -+ promise: function( type, object ) { -+ if ( typeof type !== "string" ) { -+ object = type; -+ type = undefined; -+ } -+ type = type || "fx"; -+ var defer = jQuery.Deferred(), -+ elements = this, -+ i = elements.length, -+ count = 1, -+ deferDataKey = type + "defer", -+ queueDataKey = type + "queue", -+ markDataKey = type + "mark", -+ tmp; -+ function resolve() { -+ if ( !( --count ) ) { -+ defer.resolveWith( elements, [ elements ] ); -+ } -+ } -+ while( i-- ) { -+ if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || -+ ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || -+ jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && -+ jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) { -+ count++; -+ tmp.add( resolve ); -+ } -+ } -+ resolve(); -+ return defer.promise( object ); -+ } -+}); -+ -+ -+ -+ -+var rclass = /[\n\t\r]/g, -+ rspace = /\s+/, -+ rreturn = /\r/g, -+ rtype = /^(?:button|input)$/i, -+ rfocusable = /^(?:button|input|object|select|textarea)$/i, -+ rclickable = /^a(?:rea)?$/i, -+ rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, -+ getSetAttribute = jQuery.support.getSetAttribute, -+ nodeHook, boolHook, fixSpecified; -+ -+jQuery.fn.extend({ -+ attr: function( name, value ) { -+ return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); -+ }, -+ -+ removeAttr: function( name ) { -+ return this.each(function() { -+ jQuery.removeAttr( this, name ); -+ }); -+ }, -+ -+ prop: function( name, value ) { -+ return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); -+ }, -+ -+ removeProp: function( name ) { -+ name = jQuery.propFix[ name ] || name; -+ return this.each(function() { -+ // try/catch handles cases where IE balks (such as removing a property on window) -+ try { -+ this[ name ] = undefined; -+ delete this[ name ]; -+ } catch( e ) {} -+ }); -+ }, -+ -+ addClass: function( value ) { -+ var classNames, i, l, elem, -+ setClass, c, cl; -+ -+ if ( jQuery.isFunction( value ) ) { -+ return this.each(function( j ) { -+ jQuery( this ).addClass( value.call(this, j, this.className) ); -+ }); -+ } -+ -+ if ( value && typeof value === "string" ) { -+ classNames = value.split( rspace ); -+ -+ for ( i = 0, l = this.length; i < l; i++ ) { -+ elem = this[ i ]; -+ -+ if ( elem.nodeType === 1 ) { -+ if ( !elem.className && classNames.length === 1 ) { -+ elem.className = value; -+ -+ } else { -+ setClass = " " + elem.className + " "; -+ -+ for ( c = 0, cl = classNames.length; c < cl; c++ ) { -+ if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { -+ setClass += classNames[ c ] + " "; -+ } -+ } -+ elem.className = jQuery.trim( setClass ); -+ } -+ } -+ } -+ } -+ -+ return this; -+ }, -+ -+ removeClass: function( value ) { -+ var classNames, i, l, elem, className, c, cl; -+ -+ if ( jQuery.isFunction( value ) ) { -+ return this.each(function( j ) { -+ jQuery( this ).removeClass( value.call(this, j, this.className) ); -+ }); -+ } -+ -+ if ( (value && typeof value === "string") || value === undefined ) { -+ classNames = ( value || "" ).split( rspace ); -+ -+ for ( i = 0, l = this.length; i < l; i++ ) { -+ elem = this[ i ]; -+ -+ if ( elem.nodeType === 1 && elem.className ) { -+ if ( value ) { -+ className = (" " + elem.className + " ").replace( rclass, " " ); -+ for ( c = 0, cl = classNames.length; c < cl; c++ ) { -+ className = className.replace(" " + classNames[ c ] + " ", " "); -+ } -+ elem.className = jQuery.trim( className ); -+ -+ } else { -+ elem.className = ""; -+ } -+ } -+ } -+ } -+ -+ return this; -+ }, -+ -+ toggleClass: function( value, stateVal ) { -+ var type = typeof value, -+ isBool = typeof stateVal === "boolean"; -+ -+ if ( jQuery.isFunction( value ) ) { -+ return this.each(function( i ) { -+ jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); -+ }); -+ } -+ -+ return this.each(function() { -+ if ( type === "string" ) { -+ // toggle individual class names -+ var className, -+ i = 0, -+ self = jQuery( this ), -+ state = stateVal, -+ classNames = value.split( rspace ); -+ -+ while ( (className = classNames[ i++ ]) ) { -+ // check each className given, space seperated list -+ state = isBool ? state : !self.hasClass( className ); -+ self[ state ? "addClass" : "removeClass" ]( className ); -+ } -+ -+ } else if ( type === "undefined" || type === "boolean" ) { -+ if ( this.className ) { -+ // store className if set -+ jQuery._data( this, "__className__", this.className ); -+ } -+ -+ // toggle whole className -+ this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; -+ } -+ }); -+ }, -+ -+ hasClass: function( selector ) { -+ var className = " " + selector + " ", -+ i = 0, -+ l = this.length; -+ for ( ; i < l; i++ ) { -+ if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { -+ return true; -+ } -+ } -+ -+ return false; -+ }, -+ -+ val: function( value ) { -+ var hooks, ret, isFunction, -+ elem = this[0]; -+ -+ if ( !arguments.length ) { -+ if ( elem ) { -+ hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; -+ -+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { -+ return ret; -+ } -+ -+ ret = elem.value; -+ -+ return typeof ret === "string" ? -+ // handle most common string cases -+ ret.replace(rreturn, "") : -+ // handle cases where value is null/undef or number -+ ret == null ? "" : ret; -+ } -+ -+ return; -+ } -+ -+ isFunction = jQuery.isFunction( value ); -+ -+ return this.each(function( i ) { -+ var self = jQuery(this), val; -+ -+ if ( this.nodeType !== 1 ) { -+ return; -+ } -+ -+ if ( isFunction ) { -+ val = value.call( this, i, self.val() ); -+ } else { -+ val = value; -+ } -+ -+ // Treat null/undefined as ""; convert numbers to string -+ if ( val == null ) { -+ val = ""; -+ } else if ( typeof val === "number" ) { -+ val += ""; -+ } else if ( jQuery.isArray( val ) ) { -+ val = jQuery.map(val, function ( value ) { -+ return value == null ? "" : value + ""; -+ }); -+ } -+ -+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; -+ -+ // If set returns undefined, fall back to normal setting -+ if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { -+ this.value = val; -+ } -+ }); -+ } -+}); -+ -+jQuery.extend({ -+ valHooks: { -+ option: { -+ get: function( elem ) { -+ // attributes.value is undefined in Blackberry 4.7 but -+ // uses .value. See #6932 -+ var val = elem.attributes.value; -+ return !val || val.specified ? elem.value : elem.text; -+ } -+ }, -+ select: { -+ get: function( elem ) { -+ var value, i, max, option, -+ index = elem.selectedIndex, -+ values = [], -+ options = elem.options, -+ one = elem.type === "select-one"; -+ -+ // Nothing was selected -+ if ( index < 0 ) { -+ return null; -+ } -+ -+ // Loop through all the selected options -+ i = one ? index : 0; -+ max = one ? index + 1 : options.length; -+ for ( ; i < max; i++ ) { -+ option = options[ i ]; -+ -+ // Don't return options that are disabled or in a disabled optgroup -+ if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && -+ (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { -+ -+ // Get the specific value for the option -+ value = jQuery( option ).val(); -+ -+ // We don't need an array for one selects -+ if ( one ) { -+ return value; -+ } -+ -+ // Multi-Selects return an array -+ values.push( value ); -+ } -+ } -+ -+ // Fixes Bug #2551 -- select.val() broken in IE after form.reset() -+ if ( one && !values.length && options.length ) { -+ return jQuery( options[ index ] ).val(); -+ } -+ -+ return values; -+ }, -+ -+ set: function( elem, value ) { -+ var values = jQuery.makeArray( value ); -+ -+ jQuery(elem).find("option").each(function() { -+ this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; -+ }); -+ -+ if ( !values.length ) { -+ elem.selectedIndex = -1; -+ } -+ return values; -+ } -+ } -+ }, -+ -+ attrFn: { -+ val: true, -+ css: true, -+ html: true, -+ text: true, -+ data: true, -+ width: true, -+ height: true, -+ offset: true -+ }, -+ -+ attr: function( elem, name, value, pass ) { -+ var ret, hooks, notxml, -+ nType = elem.nodeType; -+ -+ // don't get/set attributes on text, comment and attribute nodes -+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { -+ return; -+ } -+ -+ if ( pass && name in jQuery.attrFn ) { -+ return jQuery( elem )[ name ]( value ); -+ } -+ -+ // Fallback to prop when attributes are not supported -+ if ( typeof elem.getAttribute === "undefined" ) { -+ return jQuery.prop( elem, name, value ); -+ } -+ -+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); -+ -+ // All attributes are lowercase -+ // Grab necessary hook if one is defined -+ if ( notxml ) { -+ name = name.toLowerCase(); -+ hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); -+ } -+ -+ if ( value !== undefined ) { -+ -+ if ( value === null ) { -+ jQuery.removeAttr( elem, name ); -+ return; -+ -+ } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { -+ return ret; -+ -+ } else { -+ elem.setAttribute( name, "" + value ); -+ return value; -+ } -+ -+ } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { -+ return ret; -+ -+ } else { -+ -+ ret = elem.getAttribute( name ); -+ -+ // Non-existent attributes return null, we normalize to undefined -+ return ret === null ? -+ undefined : -+ ret; -+ } -+ }, -+ -+ removeAttr: function( elem, value ) { -+ var propName, attrNames, name, l, isBool, -+ i = 0; -+ -+ if ( value && elem.nodeType === 1 ) { -+ attrNames = value.toLowerCase().split( rspace ); -+ l = attrNames.length; -+ -+ for ( ; i < l; i++ ) { -+ name = attrNames[ i ]; -+ -+ if ( name ) { -+ propName = jQuery.propFix[ name ] || name; -+ isBool = rboolean.test( name ); -+ -+ // See #9699 for explanation of this approach (setting first, then removal) -+ // Do not do this for boolean attributes (see #10870) -+ if ( !isBool ) { -+ jQuery.attr( elem, name, "" ); -+ } -+ elem.removeAttribute( getSetAttribute ? name : propName ); -+ -+ // Set corresponding property to false for boolean attributes -+ if ( isBool && propName in elem ) { -+ elem[ propName ] = false; -+ } -+ } -+ } -+ } -+ }, -+ -+ attrHooks: { -+ type: { -+ set: function( elem, value ) { -+ // We can't allow the type property to be changed (since it causes problems in IE) -+ if ( rtype.test( elem.nodeName ) && elem.parentNode ) { -+ jQuery.error( "type property can't be changed" ); -+ } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { -+ // Setting the type on a radio button after the value resets the value in IE6-9 -+ // Reset value to it's default in case type is set after value -+ // This is for element creation -+ var val = elem.value; -+ elem.setAttribute( "type", value ); -+ if ( val ) { -+ elem.value = val; -+ } -+ return value; -+ } -+ } -+ }, -+ // Use the value property for back compat -+ // Use the nodeHook for button elements in IE6/7 (#1954) -+ value: { -+ get: function( elem, name ) { -+ if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { -+ return nodeHook.get( elem, name ); -+ } -+ return name in elem ? -+ elem.value : -+ null; -+ }, -+ set: function( elem, value, name ) { -+ if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { -+ return nodeHook.set( elem, value, name ); -+ } -+ // Does not return so that setAttribute is also used -+ elem.value = value; -+ } -+ } -+ }, -+ -+ propFix: { -+ tabindex: "tabIndex", -+ readonly: "readOnly", -+ "for": "htmlFor", -+ "class": "className", -+ maxlength: "maxLength", -+ cellspacing: "cellSpacing", -+ cellpadding: "cellPadding", -+ rowspan: "rowSpan", -+ colspan: "colSpan", -+ usemap: "useMap", -+ frameborder: "frameBorder", -+ contenteditable: "contentEditable" -+ }, -+ -+ prop: function( elem, name, value ) { -+ var ret, hooks, notxml, -+ nType = elem.nodeType; -+ -+ // don't get/set properties on text, comment and attribute nodes -+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { -+ return; -+ } -+ -+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); -+ -+ if ( notxml ) { -+ // Fix name and attach hooks -+ name = jQuery.propFix[ name ] || name; -+ hooks = jQuery.propHooks[ name ]; -+ } -+ -+ if ( value !== undefined ) { -+ if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { -+ return ret; -+ -+ } else { -+ return ( elem[ name ] = value ); -+ } -+ -+ } else { -+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { -+ return ret; -+ -+ } else { -+ return elem[ name ]; -+ } -+ } -+ }, -+ -+ propHooks: { -+ tabIndex: { -+ get: function( elem ) { -+ // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set -+ // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ -+ var attributeNode = elem.getAttributeNode("tabindex"); -+ -+ return attributeNode && attributeNode.specified ? -+ parseInt( attributeNode.value, 10 ) : -+ rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? -+ 0 : -+ undefined; -+ } -+ } -+ } -+}); -+ -+// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional) -+jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex; -+ -+// Hook for boolean attributes -+boolHook = { -+ get: function( elem, name ) { -+ // Align boolean attributes with corresponding properties -+ // Fall back to attribute presence where some booleans are not supported -+ var attrNode, -+ property = jQuery.prop( elem, name ); -+ return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? -+ name.toLowerCase() : -+ undefined; -+ }, -+ set: function( elem, value, name ) { -+ var propName; -+ if ( value === false ) { -+ // Remove boolean attributes when set to false -+ jQuery.removeAttr( elem, name ); -+ } else { -+ // value is true since we know at this point it's type boolean and not false -+ // Set boolean attributes to the same name and set the DOM property -+ propName = jQuery.propFix[ name ] || name; -+ if ( propName in elem ) { -+ // Only set the IDL specifically if it already exists on the element -+ elem[ propName ] = true; -+ } -+ -+ elem.setAttribute( name, name.toLowerCase() ); -+ } -+ return name; -+ } -+}; -+ -+// IE6/7 do not support getting/setting some attributes with get/setAttribute -+if ( !getSetAttribute ) { -+ -+ fixSpecified = { -+ name: true, -+ id: true, -+ coords: true -+ }; -+ -+ // Use this for any attribute in IE6/7 -+ // This fixes almost every IE6/7 issue -+ nodeHook = jQuery.valHooks.button = { -+ get: function( elem, name ) { -+ var ret; -+ ret = elem.getAttributeNode( name ); -+ return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ? -+ ret.nodeValue : -+ undefined; -+ }, -+ set: function( elem, value, name ) { -+ // Set the existing or create a new attribute node -+ var ret = elem.getAttributeNode( name ); -+ if ( !ret ) { -+ ret = document.createAttribute( name ); -+ elem.setAttributeNode( ret ); -+ } -+ return ( ret.nodeValue = value + "" ); -+ } -+ }; -+ -+ // Apply the nodeHook to tabindex -+ jQuery.attrHooks.tabindex.set = nodeHook.set; -+ -+ // Set width and height to auto instead of 0 on empty string( Bug #8150 ) -+ // This is for removals -+ jQuery.each([ "width", "height" ], function( i, name ) { -+ jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { -+ set: function( elem, value ) { -+ if ( value === "" ) { -+ elem.setAttribute( name, "auto" ); -+ return value; -+ } -+ } -+ }); -+ }); -+ -+ // Set contenteditable to false on removals(#10429) -+ // Setting to empty string throws an error as an invalid value -+ jQuery.attrHooks.contenteditable = { -+ get: nodeHook.get, -+ set: function( elem, value, name ) { -+ if ( value === "" ) { -+ value = "false"; -+ } -+ nodeHook.set( elem, value, name ); -+ } -+ }; -+} -+ -+ -+// Some attributes require a special call on IE -+if ( !jQuery.support.hrefNormalized ) { -+ jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { -+ jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { -+ get: function( elem ) { -+ var ret = elem.getAttribute( name, 2 ); -+ return ret === null ? undefined : ret; -+ } -+ }); -+ }); -+} -+ -+if ( !jQuery.support.style ) { -+ jQuery.attrHooks.style = { -+ get: function( elem ) { -+ // Return undefined in the case of empty string -+ // Normalize to lowercase since IE uppercases css property names -+ return elem.style.cssText.toLowerCase() || undefined; -+ }, -+ set: function( elem, value ) { -+ return ( elem.style.cssText = "" + value ); -+ } -+ }; -+} -+ -+// Safari mis-reports the default selected property of an option -+// Accessing the parent's selectedIndex property fixes it -+if ( !jQuery.support.optSelected ) { -+ jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { -+ get: function( elem ) { -+ var parent = elem.parentNode; -+ -+ if ( parent ) { -+ parent.selectedIndex; -+ -+ // Make sure that it also works with optgroups, see #5701 -+ if ( parent.parentNode ) { -+ parent.parentNode.selectedIndex; -+ } -+ } -+ return null; -+ } -+ }); -+} -+ -+// IE6/7 call enctype encoding -+if ( !jQuery.support.enctype ) { -+ jQuery.propFix.enctype = "encoding"; -+} -+ -+// Radios and checkboxes getter/setter -+if ( !jQuery.support.checkOn ) { -+ jQuery.each([ "radio", "checkbox" ], function() { -+ jQuery.valHooks[ this ] = { -+ get: function( elem ) { -+ // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified -+ return elem.getAttribute("value") === null ? "on" : elem.value; -+ } -+ }; -+ }); -+} -+jQuery.each([ "radio", "checkbox" ], function() { -+ jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { -+ set: function( elem, value ) { -+ if ( jQuery.isArray( value ) ) { -+ return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); -+ } -+ } -+ }); -+}); -+ -+ -+ -+ -+var rformElems = /^(?:textarea|input|select)$/i, -+ rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/, -+ rhoverHack = /(?:^|\s)hover(\.\S+)?\b/, -+ rkeyEvent = /^key/, -+ rmouseEvent = /^(?:mouse|contextmenu)|click/, -+ rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, -+ rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/, -+ quickParse = function( selector ) { -+ var quick = rquickIs.exec( selector ); -+ if ( quick ) { -+ // 0 1 2 3 -+ // [ _, tag, id, class ] -+ quick[1] = ( quick[1] || "" ).toLowerCase(); -+ quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" ); -+ } -+ return quick; -+ }, -+ quickIs = function( elem, m ) { -+ var attrs = elem.attributes || {}; -+ return ( -+ (!m[1] || elem.nodeName.toLowerCase() === m[1]) && -+ (!m[2] || (attrs.id || {}).value === m[2]) && -+ (!m[3] || m[3].test( (attrs[ "class" ] || {}).value )) -+ ); -+ }, -+ hoverHack = function( events ) { -+ return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); -+ }; -+ -+/* -+ * Helper functions for managing events -- not part of the public interface. -+ * Props to Dean Edwards' addEvent library for many of the ideas. -+ */ -+jQuery.event = { -+ -+ add: function( elem, types, handler, data, selector ) { -+ -+ var elemData, eventHandle, events, -+ t, tns, type, namespaces, handleObj, -+ handleObjIn, quick, handlers, special; -+ -+ // Don't attach events to noData or text/comment nodes (allow plain objects tho) -+ if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { -+ return; -+ } -+ -+ // Caller can pass in an object of custom data in lieu of the handler -+ if ( handler.handler ) { -+ handleObjIn = handler; -+ handler = handleObjIn.handler; -+ selector = handleObjIn.selector; -+ } -+ -+ // Make sure that the handler has a unique ID, used to find/remove it later -+ if ( !handler.guid ) { -+ handler.guid = jQuery.guid++; -+ } -+ -+ // Init the element's event structure and main handler, if this is the first -+ events = elemData.events; -+ if ( !events ) { -+ elemData.events = events = {}; -+ } -+ eventHandle = elemData.handle; -+ if ( !eventHandle ) { -+ elemData.handle = eventHandle = function( e ) { -+ // Discard the second event of a jQuery.event.trigger() and -+ // when an event is called after a page has unloaded -+ return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? -+ jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : -+ undefined; -+ }; -+ // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events -+ eventHandle.elem = elem; -+ } -+ -+ // Handle multiple events separated by a space -+ // jQuery(...).bind("mouseover mouseout", fn); -+ types = jQuery.trim( hoverHack(types) ).split( " " ); -+ for ( t = 0; t < types.length; t++ ) { -+ -+ tns = rtypenamespace.exec( types[t] ) || []; -+ type = tns[1]; -+ namespaces = ( tns[2] || "" ).split( "." ).sort(); -+ -+ // If event changes its type, use the special event handlers for the changed type -+ special = jQuery.event.special[ type ] || {}; -+ -+ // If selector defined, determine special event api type, otherwise given type -+ type = ( selector ? special.delegateType : special.bindType ) || type; -+ -+ // Update special based on newly reset type -+ special = jQuery.event.special[ type ] || {}; -+ -+ // handleObj is passed to all event handlers -+ handleObj = jQuery.extend({ -+ type: type, -+ origType: tns[1], -+ data: data, -+ handler: handler, -+ guid: handler.guid, -+ selector: selector, -+ quick: selector && quickParse( selector ), -+ namespace: namespaces.join(".") -+ }, handleObjIn ); -+ -+ // Init the event handler queue if we're the first -+ handlers = events[ type ]; -+ if ( !handlers ) { -+ handlers = events[ type ] = []; -+ handlers.delegateCount = 0; -+ -+ // Only use addEventListener/attachEvent if the special events handler returns false -+ if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { -+ // Bind the global event handler to the element -+ if ( elem.addEventListener ) { -+ elem.addEventListener( type, eventHandle, false ); -+ -+ } else if ( elem.attachEvent ) { -+ elem.attachEvent( "on" + type, eventHandle ); -+ } -+ } -+ } -+ -+ if ( special.add ) { -+ special.add.call( elem, handleObj ); -+ -+ if ( !handleObj.handler.guid ) { -+ handleObj.handler.guid = handler.guid; -+ } -+ } -+ -+ // Add to the element's handler list, delegates in front -+ if ( selector ) { -+ handlers.splice( handlers.delegateCount++, 0, handleObj ); -+ } else { -+ handlers.push( handleObj ); -+ } -+ -+ // Keep track of which events have ever been used, for event optimization -+ jQuery.event.global[ type ] = true; -+ } -+ -+ // Nullify elem to prevent memory leaks in IE -+ elem = null; -+ }, -+ -+ global: {}, -+ -+ // Detach an event or set of events from an element -+ remove: function( elem, types, handler, selector, mappedTypes ) { -+ -+ var elemData = jQuery.hasData( elem ) && jQuery._data( elem ), -+ t, tns, type, origType, namespaces, origCount, -+ j, events, special, handle, eventType, handleObj; -+ -+ if ( !elemData || !(events = elemData.events) ) { -+ return; -+ } -+ -+ // Once for each type.namespace in types; type may be omitted -+ types = jQuery.trim( hoverHack( types || "" ) ).split(" "); -+ for ( t = 0; t < types.length; t++ ) { -+ tns = rtypenamespace.exec( types[t] ) || []; -+ type = origType = tns[1]; -+ namespaces = tns[2]; -+ -+ // Unbind all events (on this namespace, if provided) for the element -+ if ( !type ) { -+ for ( type in events ) { -+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); -+ } -+ continue; -+ } -+ -+ special = jQuery.event.special[ type ] || {}; -+ type = ( selector? special.delegateType : special.bindType ) || type; -+ eventType = events[ type ] || []; -+ origCount = eventType.length; -+ namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null; -+ -+ // Remove matching events -+ for ( j = 0; j < eventType.length; j++ ) { -+ handleObj = eventType[ j ]; -+ -+ if ( ( mappedTypes || origType === handleObj.origType ) && -+ ( !handler || handler.guid === handleObj.guid ) && -+ ( !namespaces || namespaces.test( handleObj.namespace ) ) && -+ ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { -+ eventType.splice( j--, 1 ); -+ -+ if ( handleObj.selector ) { -+ eventType.delegateCount--; -+ } -+ if ( special.remove ) { -+ special.remove.call( elem, handleObj ); -+ } -+ } -+ } -+ -+ // Remove generic event handler if we removed something and no more handlers exist -+ // (avoids potential for endless recursion during removal of special event handlers) -+ if ( eventType.length === 0 && origCount !== eventType.length ) { -+ if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { -+ jQuery.removeEvent( elem, type, elemData.handle ); -+ } -+ -+ delete events[ type ]; -+ } -+ } -+ -+ // Remove the expando if it's no longer used -+ if ( jQuery.isEmptyObject( events ) ) { -+ handle = elemData.handle; -+ if ( handle ) { -+ handle.elem = null; -+ } -+ -+ // removeData also checks for emptiness and clears the expando if empty -+ // so use it instead of delete -+ jQuery.removeData( elem, [ "events", "handle" ], true ); -+ } -+ }, -+ -+ // Events that are safe to short-circuit if no handlers are attached. -+ // Native DOM events should not be added, they may have inline handlers. -+ customEvent: { -+ "getData": true, -+ "setData": true, -+ "changeData": true -+ }, -+ -+ trigger: function( event, data, elem, onlyHandlers ) { -+ // Don't do events on text and comment nodes -+ if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { -+ return; -+ } -+ -+ // Event object or event type -+ var type = event.type || event, -+ namespaces = [], -+ cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType; -+ -+ // focus/blur morphs to focusin/out; ensure we're not firing them right now -+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { -+ return; -+ } -+ -+ if ( type.indexOf( "!" ) >= 0 ) { -+ // Exclusive events trigger only for the exact event (no namespaces) -+ type = type.slice(0, -1); -+ exclusive = true; -+ } -+ -+ if ( type.indexOf( "." ) >= 0 ) { -+ // Namespaced trigger; create a regexp to match event type in handle() -+ namespaces = type.split("."); -+ type = namespaces.shift(); -+ namespaces.sort(); -+ } -+ -+ if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { -+ // No jQuery handlers for this event type, and it can't have inline handlers -+ return; -+ } -+ -+ // Caller can pass in an Event, Object, or just an event type string -+ event = typeof event === "object" ? -+ // jQuery.Event object -+ event[ jQuery.expando ] ? event : -+ // Object literal -+ new jQuery.Event( type, event ) : -+ // Just the event type (string) -+ new jQuery.Event( type ); -+ -+ event.type = type; -+ event.isTrigger = true; -+ event.exclusive = exclusive; -+ event.namespace = namespaces.join( "." ); -+ event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null; -+ ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; -+ -+ // Handle a global trigger -+ if ( !elem ) { -+ -+ // TODO: Stop taunting the data cache; remove global events and always attach to document -+ cache = jQuery.cache; -+ for ( i in cache ) { -+ if ( cache[ i ].events && cache[ i ].events[ type ] ) { -+ jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); -+ } -+ } -+ return; -+ } -+ -+ // Clean up the event in case it is being reused -+ event.result = undefined; -+ if ( !event.target ) { -+ event.target = elem; -+ } -+ -+ // Clone any incoming data and prepend the event, creating the handler arg list -+ data = data != null ? jQuery.makeArray( data ) : []; -+ data.unshift( event ); -+ -+ // Allow special events to draw outside the lines -+ special = jQuery.event.special[ type ] || {}; -+ if ( special.trigger && special.trigger.apply( elem, data ) === false ) { -+ return; -+ } -+ -+ // Determine event propagation path in advance, per W3C events spec (#9951) -+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) -+ eventPath = [[ elem, special.bindType || type ]]; -+ if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { -+ -+ bubbleType = special.delegateType || type; -+ cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; -+ old = null; -+ for ( ; cur; cur = cur.parentNode ) { -+ eventPath.push([ cur, bubbleType ]); -+ old = cur; -+ } -+ -+ // Only add window if we got to document (e.g., not plain obj or detached DOM) -+ if ( old && old === elem.ownerDocument ) { -+ eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); -+ } -+ } -+ -+ // Fire handlers on the event path -+ for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { -+ -+ cur = eventPath[i][0]; -+ event.type = eventPath[i][1]; -+ -+ handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); -+ if ( handle ) { -+ handle.apply( cur, data ); -+ } -+ // Note that this is a bare JS function and not a jQuery handler -+ handle = ontype && cur[ ontype ]; -+ if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) { -+ event.preventDefault(); -+ } -+ } -+ event.type = type; -+ -+ // If nobody prevented the default action, do it now -+ if ( !onlyHandlers && !event.isDefaultPrevented() ) { -+ -+ if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && -+ !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { -+ -+ // Call a native DOM method on the target with the same name name as the event. -+ // Can't use an .isFunction() check here because IE6/7 fails that test. -+ // Don't do default actions on window, that's where global variables be (#6170) -+ // IE<9 dies on focus/blur to hidden element (#1486) -+ if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { -+ -+ // Don't re-trigger an onFOO event when we call its FOO() method -+ old = elem[ ontype ]; -+ -+ if ( old ) { -+ elem[ ontype ] = null; -+ } -+ -+ // Prevent re-triggering of the same event, since we already bubbled it above -+ jQuery.event.triggered = type; -+ elem[ type ](); -+ jQuery.event.triggered = undefined; -+ -+ if ( old ) { -+ elem[ ontype ] = old; -+ } -+ } -+ } -+ } -+ -+ return event.result; -+ }, -+ -+ dispatch: function( event ) { -+ -+ // Make a writable jQuery.Event from the native event object -+ event = jQuery.event.fix( event || window.event ); -+ -+ var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), -+ delegateCount = handlers.delegateCount, -+ args = [].slice.call( arguments, 0 ), -+ run_all = !event.exclusive && !event.namespace, -+ special = jQuery.event.special[ event.type ] || {}, -+ handlerQueue = [], -+ i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related; -+ -+ // Use the fix-ed jQuery.Event rather than the (read-only) native event -+ args[0] = event; -+ event.delegateTarget = this; -+ -+ // Call the preDispatch hook for the mapped type, and let it bail if desired -+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { -+ return; -+ } -+ -+ // Determine handlers that should run if there are delegated events -+ // Avoid non-left-click bubbling in Firefox (#3861) -+ if ( delegateCount && !(event.button && event.type === "click") ) { -+ -+ // Pregenerate a single jQuery object for reuse with .is() -+ jqcur = jQuery(this); -+ jqcur.context = this.ownerDocument || this; -+ -+ for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { -+ -+ // Don't process events on disabled elements (#6911, #8165) -+ if ( cur.disabled !== true ) { -+ selMatch = {}; -+ matches = []; -+ jqcur[0] = cur; -+ for ( i = 0; i < delegateCount; i++ ) { -+ handleObj = handlers[ i ]; -+ sel = handleObj.selector; -+ -+ if ( selMatch[ sel ] === undefined ) { -+ selMatch[ sel ] = ( -+ handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel ) -+ ); -+ } -+ if ( selMatch[ sel ] ) { -+ matches.push( handleObj ); -+ } -+ } -+ if ( matches.length ) { -+ handlerQueue.push({ elem: cur, matches: matches }); -+ } -+ } -+ } -+ } -+ -+ // Add the remaining (directly-bound) handlers -+ if ( handlers.length > delegateCount ) { -+ handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); -+ } -+ -+ // Run delegates first; they may want to stop propagation beneath us -+ for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { -+ matched = handlerQueue[ i ]; -+ event.currentTarget = matched.elem; -+ -+ for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { -+ handleObj = matched.matches[ j ]; -+ -+ // Triggered event must either 1) be non-exclusive and have no namespace, or -+ // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). -+ if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { -+ -+ event.data = handleObj.data; -+ event.handleObj = handleObj; -+ -+ ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) -+ .apply( matched.elem, args ); -+ -+ if ( ret !== undefined ) { -+ event.result = ret; -+ if ( ret === false ) { -+ event.preventDefault(); -+ event.stopPropagation(); -+ } -+ } -+ } -+ } -+ } -+ -+ // Call the postDispatch hook for the mapped type -+ if ( special.postDispatch ) { -+ special.postDispatch.call( this, event ); -+ } -+ -+ return event.result; -+ }, -+ -+ // Includes some event props shared by KeyEvent and MouseEvent -+ // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** -+ props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), -+ -+ fixHooks: {}, -+ -+ keyHooks: { -+ props: "char charCode key keyCode".split(" "), -+ filter: function( event, original ) { -+ -+ // Add which for key events -+ if ( event.which == null ) { -+ event.which = original.charCode != null ? original.charCode : original.keyCode; -+ } -+ -+ return event; -+ } -+ }, -+ -+ mouseHooks: { -+ props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), -+ filter: function( event, original ) { -+ var eventDoc, doc, body, -+ button = original.button, -+ fromElement = original.fromElement; -+ -+ // Calculate pageX/Y if missing and clientX/Y available -+ if ( event.pageX == null && original.clientX != null ) { -+ eventDoc = event.target.ownerDocument || document; -+ doc = eventDoc.documentElement; -+ body = eventDoc.body; -+ -+ event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); -+ event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); -+ } -+ -+ // Add relatedTarget, if necessary -+ if ( !event.relatedTarget && fromElement ) { -+ event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; -+ } -+ -+ // Add which for click: 1 === left; 2 === middle; 3 === right -+ // Note: button is not normalized, so don't use it -+ if ( !event.which && button !== undefined ) { -+ event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); -+ } -+ -+ return event; -+ } -+ }, -+ -+ fix: function( event ) { -+ if ( event[ jQuery.expando ] ) { -+ return event; -+ } -+ -+ // Create a writable copy of the event object and normalize some properties -+ var i, prop, -+ originalEvent = event, -+ fixHook = jQuery.event.fixHooks[ event.type ] || {}, -+ copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; -+ -+ event = jQuery.Event( originalEvent ); -+ -+ for ( i = copy.length; i; ) { -+ prop = copy[ --i ]; -+ event[ prop ] = originalEvent[ prop ]; -+ } -+ -+ // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) -+ if ( !event.target ) { -+ event.target = originalEvent.srcElement || document; -+ } -+ -+ // Target should not be a text node (#504, Safari) -+ if ( event.target.nodeType === 3 ) { -+ event.target = event.target.parentNode; -+ } -+ -+ // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8) -+ if ( event.metaKey === undefined ) { -+ event.metaKey = event.ctrlKey; -+ } -+ -+ return fixHook.filter? fixHook.filter( event, originalEvent ) : event; -+ }, -+ -+ special: { -+ ready: { -+ // Make sure the ready event is setup -+ setup: jQuery.bindReady -+ }, -+ -+ load: { -+ // Prevent triggered image.load events from bubbling to window.load -+ noBubble: true -+ }, -+ -+ focus: { -+ delegateType: "focusin" -+ }, -+ blur: { -+ delegateType: "focusout" -+ }, -+ -+ beforeunload: { -+ setup: function( data, namespaces, eventHandle ) { -+ // We only want to do this special case on windows -+ if ( jQuery.isWindow( this ) ) { -+ this.onbeforeunload = eventHandle; -+ } -+ }, -+ -+ teardown: function( namespaces, eventHandle ) { -+ if ( this.onbeforeunload === eventHandle ) { -+ this.onbeforeunload = null; -+ } -+ } -+ } -+ }, -+ -+ simulate: function( type, elem, event, bubble ) { -+ // Piggyback on a donor event to simulate a different one. -+ // Fake originalEvent to avoid donor's stopPropagation, but if the -+ // simulated event prevents default then we do the same on the donor. -+ var e = jQuery.extend( -+ new jQuery.Event(), -+ event, -+ { type: type, -+ isSimulated: true, -+ originalEvent: {} -+ } -+ ); -+ if ( bubble ) { -+ jQuery.event.trigger( e, null, elem ); -+ } else { -+ jQuery.event.dispatch.call( elem, e ); -+ } -+ if ( e.isDefaultPrevented() ) { -+ event.preventDefault(); -+ } -+ } -+}; -+ -+// Some plugins are using, but it's undocumented/deprecated and will be removed. -+// The 1.7 special event interface should provide all the hooks needed now. -+jQuery.event.handle = jQuery.event.dispatch; -+ -+jQuery.removeEvent = document.removeEventListener ? -+ function( elem, type, handle ) { -+ if ( elem.removeEventListener ) { -+ elem.removeEventListener( type, handle, false ); -+ } -+ } : -+ function( elem, type, handle ) { -+ if ( elem.detachEvent ) { -+ elem.detachEvent( "on" + type, handle ); -+ } -+ }; -+ -+jQuery.Event = function( src, props ) { -+ // Allow instantiation without the 'new' keyword -+ if ( !(this instanceof jQuery.Event) ) { -+ return new jQuery.Event( src, props ); -+ } -+ -+ // Event object -+ if ( src && src.type ) { -+ this.originalEvent = src; -+ this.type = src.type; -+ -+ // Events bubbling up the document may have been marked as prevented -+ // by a handler lower down the tree; reflect the correct value. -+ this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || -+ src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; -+ -+ // Event type -+ } else { -+ this.type = src; -+ } -+ -+ // Put explicitly provided properties onto the event object -+ if ( props ) { -+ jQuery.extend( this, props ); -+ } -+ -+ // Create a timestamp if incoming event doesn't have one -+ this.timeStamp = src && src.timeStamp || jQuery.now(); -+ -+ // Mark it as fixed -+ this[ jQuery.expando ] = true; -+}; -+ -+function returnFalse() { -+ return false; -+} -+function returnTrue() { -+ return true; -+} -+ -+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -+jQuery.Event.prototype = { -+ preventDefault: function() { -+ this.isDefaultPrevented = returnTrue; -+ -+ var e = this.originalEvent; -+ if ( !e ) { -+ return; -+ } -+ -+ // if preventDefault exists run it on the original event -+ if ( e.preventDefault ) { -+ e.preventDefault(); -+ -+ // otherwise set the returnValue property of the original event to false (IE) -+ } else { -+ e.returnValue = false; -+ } -+ }, -+ stopPropagation: function() { -+ this.isPropagationStopped = returnTrue; -+ -+ var e = this.originalEvent; -+ if ( !e ) { -+ return; -+ } -+ // if stopPropagation exists run it on the original event -+ if ( e.stopPropagation ) { -+ e.stopPropagation(); -+ } -+ // otherwise set the cancelBubble property of the original event to true (IE) -+ e.cancelBubble = true; -+ }, -+ stopImmediatePropagation: function() { -+ this.isImmediatePropagationStopped = returnTrue; -+ this.stopPropagation(); -+ }, -+ isDefaultPrevented: returnFalse, -+ isPropagationStopped: returnFalse, -+ isImmediatePropagationStopped: returnFalse -+}; -+ -+// Create mouseenter/leave events using mouseover/out and event-time checks -+jQuery.each({ -+ mouseenter: "mouseover", -+ mouseleave: "mouseout" -+}, function( orig, fix ) { -+ jQuery.event.special[ orig ] = { -+ delegateType: fix, -+ bindType: fix, -+ -+ handle: function( event ) { -+ var target = this, -+ related = event.relatedTarget, -+ handleObj = event.handleObj, -+ selector = handleObj.selector, -+ ret; -+ -+ // For mousenter/leave call the handler if related is outside the target. -+ // NB: No relatedTarget if the mouse left/entered the browser window -+ if ( !related || (related !== target && !jQuery.contains( target, related )) ) { -+ event.type = handleObj.origType; -+ ret = handleObj.handler.apply( this, arguments ); -+ event.type = fix; -+ } -+ return ret; -+ } -+ }; -+}); -+ -+// IE submit delegation -+if ( !jQuery.support.submitBubbles ) { -+ -+ jQuery.event.special.submit = { -+ setup: function() { -+ // Only need this for delegated form submit events -+ if ( jQuery.nodeName( this, "form" ) ) { -+ return false; -+ } -+ -+ // Lazy-add a submit handler when a descendant form may potentially be submitted -+ jQuery.event.add( this, "click._submit keypress._submit", function( e ) { -+ // Node name check avoids a VML-related crash in IE (#9807) -+ var elem = e.target, -+ form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; -+ if ( form && !form._submit_attached ) { -+ jQuery.event.add( form, "submit._submit", function( event ) { -+ event._submit_bubble = true; -+ }); -+ form._submit_attached = true; -+ } -+ }); -+ // return undefined since we don't need an event listener -+ }, -+ -+ postDispatch: function( event ) { -+ // If form was submitted by the user, bubble the event up the tree -+ if ( event._submit_bubble ) { -+ delete event._submit_bubble; -+ if ( this.parentNode && !event.isTrigger ) { -+ jQuery.event.simulate( "submit", this.parentNode, event, true ); -+ } -+ } -+ }, -+ -+ teardown: function() { -+ // Only need this for delegated form submit events -+ if ( jQuery.nodeName( this, "form" ) ) { -+ return false; -+ } -+ -+ // Remove delegated handlers; cleanData eventually reaps submit handlers attached above -+ jQuery.event.remove( this, "._submit" ); -+ } -+ }; -+} -+ -+// IE change delegation and checkbox/radio fix -+if ( !jQuery.support.changeBubbles ) { -+ -+ jQuery.event.special.change = { -+ -+ setup: function() { -+ -+ if ( rformElems.test( this.nodeName ) ) { -+ // IE doesn't fire change on a check/radio until blur; trigger it on click -+ // after a propertychange. Eat the blur-change in special.change.handle. -+ // This still fires onchange a second time for check/radio after blur. -+ if ( this.type === "checkbox" || this.type === "radio" ) { -+ jQuery.event.add( this, "propertychange._change", function( event ) { -+ if ( event.originalEvent.propertyName === "checked" ) { -+ this._just_changed = true; -+ } -+ }); -+ jQuery.event.add( this, "click._change", function( event ) { -+ if ( this._just_changed && !event.isTrigger ) { -+ this._just_changed = false; -+ jQuery.event.simulate( "change", this, event, true ); -+ } -+ }); -+ } -+ return false; -+ } -+ // Delegated event; lazy-add a change handler on descendant inputs -+ jQuery.event.add( this, "beforeactivate._change", function( e ) { -+ var elem = e.target; -+ -+ if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) { -+ jQuery.event.add( elem, "change._change", function( event ) { -+ if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { -+ jQuery.event.simulate( "change", this.parentNode, event, true ); -+ } -+ }); -+ elem._change_attached = true; -+ } -+ }); -+ }, -+ -+ handle: function( event ) { -+ var elem = event.target; -+ -+ // Swallow native change events from checkbox/radio, we already triggered them above -+ if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { -+ return event.handleObj.handler.apply( this, arguments ); -+ } -+ }, -+ -+ teardown: function() { -+ jQuery.event.remove( this, "._change" ); -+ -+ return rformElems.test( this.nodeName ); -+ } -+ }; -+} -+ -+// Create "bubbling" focus and blur events -+if ( !jQuery.support.focusinBubbles ) { -+ jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { -+ -+ // Attach a single capturing handler while someone wants focusin/focusout -+ var attaches = 0, -+ handler = function( event ) { -+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); -+ }; -+ -+ jQuery.event.special[ fix ] = { -+ setup: function() { -+ if ( attaches++ === 0 ) { -+ document.addEventListener( orig, handler, true ); -+ } -+ }, -+ teardown: function() { -+ if ( --attaches === 0 ) { -+ document.removeEventListener( orig, handler, true ); -+ } -+ } -+ }; -+ }); -+} -+ -+jQuery.fn.extend({ -+ -+ on: function( types, selector, data, fn, /*INTERNAL*/ one ) { -+ var origFn, type; -+ -+ // Types can be a map of types/handlers -+ if ( typeof types === "object" ) { -+ // ( types-Object, selector, data ) -+ if ( typeof selector !== "string" ) { // && selector != null -+ // ( types-Object, data ) -+ data = data || selector; -+ selector = undefined; -+ } -+ for ( type in types ) { -+ this.on( type, selector, data, types[ type ], one ); -+ } -+ return this; -+ } -+ -+ if ( data == null && fn == null ) { -+ // ( types, fn ) -+ fn = selector; -+ data = selector = undefined; -+ } else if ( fn == null ) { -+ if ( typeof selector === "string" ) { -+ // ( types, selector, fn ) -+ fn = data; -+ data = undefined; -+ } else { -+ // ( types, data, fn ) -+ fn = data; -+ data = selector; -+ selector = undefined; -+ } -+ } -+ if ( fn === false ) { -+ fn = returnFalse; -+ } else if ( !fn ) { -+ return this; -+ } -+ -+ if ( one === 1 ) { -+ origFn = fn; -+ fn = function( event ) { -+ // Can use an empty set, since event contains the info -+ jQuery().off( event ); -+ return origFn.apply( this, arguments ); -+ }; -+ // Use same guid so caller can remove using origFn -+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); -+ } -+ return this.each( function() { -+ jQuery.event.add( this, types, fn, data, selector ); -+ }); -+ }, -+ one: function( types, selector, data, fn ) { -+ return this.on( types, selector, data, fn, 1 ); -+ }, -+ off: function( types, selector, fn ) { -+ if ( types && types.preventDefault && types.handleObj ) { -+ // ( event ) dispatched jQuery.Event -+ var handleObj = types.handleObj; -+ jQuery( types.delegateTarget ).off( -+ handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, -+ handleObj.selector, -+ handleObj.handler -+ ); -+ return this; -+ } -+ if ( typeof types === "object" ) { -+ // ( types-object [, selector] ) -+ for ( var type in types ) { -+ this.off( type, selector, types[ type ] ); -+ } -+ return this; -+ } -+ if ( selector === false || typeof selector === "function" ) { -+ // ( types [, fn] ) -+ fn = selector; -+ selector = undefined; -+ } -+ if ( fn === false ) { -+ fn = returnFalse; -+ } -+ return this.each(function() { -+ jQuery.event.remove( this, types, fn, selector ); -+ }); -+ }, -+ -+ bind: function( types, data, fn ) { -+ return this.on( types, null, data, fn ); -+ }, -+ unbind: function( types, fn ) { -+ return this.off( types, null, fn ); -+ }, -+ -+ live: function( types, data, fn ) { -+ jQuery( this.context ).on( types, this.selector, data, fn ); -+ return this; -+ }, -+ die: function( types, fn ) { -+ jQuery( this.context ).off( types, this.selector || "**", fn ); -+ return this; -+ }, -+ -+ delegate: function( selector, types, data, fn ) { -+ return this.on( types, selector, data, fn ); -+ }, -+ undelegate: function( selector, types, fn ) { -+ // ( namespace ) or ( selector, types [, fn] ) -+ return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn ); -+ }, -+ -+ trigger: function( type, data ) { -+ return this.each(function() { -+ jQuery.event.trigger( type, data, this ); -+ }); -+ }, -+ triggerHandler: function( type, data ) { -+ if ( this[0] ) { -+ return jQuery.event.trigger( type, data, this[0], true ); -+ } -+ }, -+ -+ toggle: function( fn ) { -+ // Save reference to arguments for access in closure -+ var args = arguments, -+ guid = fn.guid || jQuery.guid++, -+ i = 0, -+ toggler = function( event ) { -+ // Figure out which function to execute -+ var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; -+ jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); -+ -+ // Make sure that clicks stop -+ event.preventDefault(); -+ -+ // and execute the function -+ return args[ lastToggle ].apply( this, arguments ) || false; -+ }; -+ -+ // link all the functions, so any of them can unbind this click handler -+ toggler.guid = guid; -+ while ( i < args.length ) { -+ args[ i++ ].guid = guid; -+ } -+ -+ return this.click( toggler ); -+ }, -+ -+ hover: function( fnOver, fnOut ) { -+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); -+ } -+}); -+ -+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + -+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + -+ "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { -+ -+ // Handle event binding -+ jQuery.fn[ name ] = function( data, fn ) { -+ if ( fn == null ) { -+ fn = data; -+ data = null; -+ } -+ -+ return arguments.length > 0 ? -+ this.on( name, null, data, fn ) : -+ this.trigger( name ); -+ }; -+ -+ if ( jQuery.attrFn ) { -+ jQuery.attrFn[ name ] = true; -+ } -+ -+ if ( rkeyEvent.test( name ) ) { -+ jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; -+ } -+ -+ if ( rmouseEvent.test( name ) ) { -+ jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; -+ } -+}); -+ -+ -+ -+/*! -+ * Sizzle CSS Selector Engine -+ * Copyright 2011, The Dojo Foundation -+ * Released under the MIT, BSD, and GPL Licenses. -+ * More information: http://sizzlejs.com/ -+ */ -+(function(){ -+ -+var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, -+ expando = "sizcache" + (Math.random() + '').replace('.', ''), -+ done = 0, -+ toString = Object.prototype.toString, -+ hasDuplicate = false, -+ baseHasDuplicate = true, -+ rBackslash = /\\/g, -+ rReturn = /\r\n/g, -+ rNonWord = /\W/; -+ -+// Here we check if the JavaScript engine is using some sort of -+// optimization where it does not always call our comparision -+// function. If that is the case, discard the hasDuplicate value. -+// Thus far that includes Google Chrome. -+[0, 0].sort(function() { -+ baseHasDuplicate = false; -+ return 0; -+}); -+ -+var Sizzle = function( selector, context, results, seed ) { -+ results = results || []; -+ context = context || document; -+ -+ var origContext = context; -+ -+ if ( context.nodeType !== 1 && context.nodeType !== 9 ) { -+ return []; -+ } -+ -+ if ( !selector || typeof selector !== "string" ) { -+ return results; -+ } -+ -+ var m, set, checkSet, extra, ret, cur, pop, i, -+ prune = true, -+ contextXML = Sizzle.isXML( context ), -+ parts = [], -+ soFar = selector; -+ -+ // Reset the position of the chunker regexp (start from head) -+ do { -+ chunker.exec( "" ); -+ m = chunker.exec( soFar ); -+ -+ if ( m ) { -+ soFar = m[3]; -+ -+ parts.push( m[1] ); -+ -+ if ( m[2] ) { -+ extra = m[3]; -+ break; -+ } -+ } -+ } while ( m ); -+ -+ if ( parts.length > 1 && origPOS.exec( selector ) ) { -+ -+ if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { -+ set = posProcess( parts[0] + parts[1], context, seed ); -+ -+ } else { -+ set = Expr.relative[ parts[0] ] ? -+ [ context ] : -+ Sizzle( parts.shift(), context ); -+ -+ while ( parts.length ) { -+ selector = parts.shift(); -+ -+ if ( Expr.relative[ selector ] ) { -+ selector += parts.shift(); -+ } -+ -+ set = posProcess( selector, set, seed ); -+ } -+ } -+ -+ } else { -+ // Take a shortcut and set the context if the root selector is an ID -+ // (but not if it'll be faster if the inner selector is an ID) -+ if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && -+ Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { -+ -+ ret = Sizzle.find( parts.shift(), context, contextXML ); -+ context = ret.expr ? -+ Sizzle.filter( ret.expr, ret.set )[0] : -+ ret.set[0]; -+ } -+ -+ if ( context ) { -+ ret = seed ? -+ { expr: parts.pop(), set: makeArray(seed) } : -+ Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); -+ -+ set = ret.expr ? -+ Sizzle.filter( ret.expr, ret.set ) : -+ ret.set; -+ -+ if ( parts.length > 0 ) { -+ checkSet = makeArray( set ); -+ -+ } else { -+ prune = false; -+ } -+ -+ while ( parts.length ) { -+ cur = parts.pop(); -+ pop = cur; -+ -+ if ( !Expr.relative[ cur ] ) { -+ cur = ""; -+ } else { -+ pop = parts.pop(); -+ } -+ -+ if ( pop == null ) { -+ pop = context; -+ } -+ -+ Expr.relative[ cur ]( checkSet, pop, contextXML ); -+ } -+ -+ } else { -+ checkSet = parts = []; -+ } -+ } -+ -+ if ( !checkSet ) { -+ checkSet = set; -+ } -+ -+ if ( !checkSet ) { -+ Sizzle.error( cur || selector ); -+ } -+ -+ if ( toString.call(checkSet) === "[object Array]" ) { -+ if ( !prune ) { -+ results.push.apply( results, checkSet ); -+ -+ } else if ( context && context.nodeType === 1 ) { -+ for ( i = 0; checkSet[i] != null; i++ ) { -+ if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { -+ results.push( set[i] ); -+ } -+ } -+ -+ } else { -+ for ( i = 0; checkSet[i] != null; i++ ) { -+ if ( checkSet[i] && checkSet[i].nodeType === 1 ) { -+ results.push( set[i] ); -+ } -+ } -+ } -+ -+ } else { -+ makeArray( checkSet, results ); -+ } -+ -+ if ( extra ) { -+ Sizzle( extra, origContext, results, seed ); -+ Sizzle.uniqueSort( results ); -+ } -+ -+ return results; -+}; -+ -+Sizzle.uniqueSort = function( results ) { -+ if ( sortOrder ) { -+ hasDuplicate = baseHasDuplicate; -+ results.sort( sortOrder ); -+ -+ if ( hasDuplicate ) { -+ for ( var i = 1; i < results.length; i++ ) { -+ if ( results[i] === results[ i - 1 ] ) { -+ results.splice( i--, 1 ); -+ } -+ } -+ } -+ } -+ -+ return results; -+}; -+ -+Sizzle.matches = function( expr, set ) { -+ return Sizzle( expr, null, null, set ); -+}; -+ -+Sizzle.matchesSelector = function( node, expr ) { -+ return Sizzle( expr, null, null, [node] ).length > 0; -+}; -+ -+Sizzle.find = function( expr, context, isXML ) { -+ var set, i, len, match, type, left; -+ -+ if ( !expr ) { -+ return []; -+ } -+ -+ for ( i = 0, len = Expr.order.length; i < len; i++ ) { -+ type = Expr.order[i]; -+ -+ if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { -+ left = match[1]; -+ match.splice( 1, 1 ); -+ -+ if ( left.substr( left.length - 1 ) !== "\\" ) { -+ match[1] = (match[1] || "").replace( rBackslash, "" ); -+ set = Expr.find[ type ]( match, context, isXML ); -+ -+ if ( set != null ) { -+ expr = expr.replace( Expr.match[ type ], "" ); -+ break; -+ } -+ } -+ } -+ } -+ -+ if ( !set ) { -+ set = typeof context.getElementsByTagName !== "undefined" ? -+ context.getElementsByTagName( "*" ) : -+ []; -+ } -+ -+ return { set: set, expr: expr }; -+}; -+ -+Sizzle.filter = function( expr, set, inplace, not ) { -+ var match, anyFound, -+ type, found, item, filter, left, -+ i, pass, -+ old = expr, -+ result = [], -+ curLoop = set, -+ isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); -+ -+ while ( expr && set.length ) { -+ for ( type in Expr.filter ) { -+ if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { -+ filter = Expr.filter[ type ]; -+ left = match[1]; -+ -+ anyFound = false; -+ -+ match.splice(1,1); -+ -+ if ( left.substr( left.length - 1 ) === "\\" ) { -+ continue; -+ } -+ -+ if ( curLoop === result ) { -+ result = []; -+ } -+ -+ if ( Expr.preFilter[ type ] ) { -+ match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); -+ -+ if ( !match ) { -+ anyFound = found = true; -+ -+ } else if ( match === true ) { -+ continue; -+ } -+ } -+ -+ if ( match ) { -+ for ( i = 0; (item = curLoop[i]) != null; i++ ) { -+ if ( item ) { -+ found = filter( item, match, i, curLoop ); -+ pass = not ^ found; -+ -+ if ( inplace && found != null ) { -+ if ( pass ) { -+ anyFound = true; -+ -+ } else { -+ curLoop[i] = false; -+ } -+ -+ } else if ( pass ) { -+ result.push( item ); -+ anyFound = true; -+ } -+ } -+ } -+ } -+ -+ if ( found !== undefined ) { -+ if ( !inplace ) { -+ curLoop = result; -+ } -+ -+ expr = expr.replace( Expr.match[ type ], "" ); -+ -+ if ( !anyFound ) { -+ return []; -+ } -+ -+ break; -+ } -+ } -+ } -+ -+ // Improper expression -+ if ( expr === old ) { -+ if ( anyFound == null ) { -+ Sizzle.error( expr ); -+ -+ } else { -+ break; -+ } -+ } -+ -+ old = expr; -+ } -+ -+ return curLoop; -+}; -+ -+Sizzle.error = function( msg ) { -+ throw new Error( "Syntax error, unrecognized expression: " + msg ); -+}; -+ -+/** -+ * Utility function for retreiving the text value of an array of DOM nodes -+ * @param {Array|Element} elem -+ */ -+var getText = Sizzle.getText = function( elem ) { -+ var i, node, -+ nodeType = elem.nodeType, -+ ret = ""; -+ -+ if ( nodeType ) { -+ if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { -+ // Use textContent || innerText for elements -+ if ( typeof elem.textContent === 'string' ) { -+ return elem.textContent; -+ } else if ( typeof elem.innerText === 'string' ) { -+ // Replace IE's carriage returns -+ return elem.innerText.replace( rReturn, '' ); -+ } else { -+ // Traverse it's children -+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling) { -+ ret += getText( elem ); -+ } -+ } -+ } else if ( nodeType === 3 || nodeType === 4 ) { -+ return elem.nodeValue; -+ } -+ } else { -+ -+ // If no nodeType, this is expected to be an array -+ for ( i = 0; (node = elem[i]); i++ ) { -+ // Do not traverse comment nodes -+ if ( node.nodeType !== 8 ) { -+ ret += getText( node ); -+ } -+ } -+ } -+ return ret; -+}; -+ -+var Expr = Sizzle.selectors = { -+ order: [ "ID", "NAME", "TAG" ], -+ -+ match: { -+ ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, -+ CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, -+ NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, -+ ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, -+ TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, -+ CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, -+ POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, -+ PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ -+ }, -+ -+ leftMatch: {}, -+ -+ attrMap: { -+ "class": "className", -+ "for": "htmlFor" -+ }, -+ -+ attrHandle: { -+ href: function( elem ) { -+ return elem.getAttribute( "href" ); -+ }, -+ type: function( elem ) { -+ return elem.getAttribute( "type" ); -+ } -+ }, -+ -+ relative: { -+ "+": function(checkSet, part){ -+ var isPartStr = typeof part === "string", -+ isTag = isPartStr && !rNonWord.test( part ), -+ isPartStrNotTag = isPartStr && !isTag; -+ -+ if ( isTag ) { -+ part = part.toLowerCase(); -+ } -+ -+ for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { -+ if ( (elem = checkSet[i]) ) { -+ while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} -+ -+ checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? -+ elem || false : -+ elem === part; -+ } -+ } -+ -+ if ( isPartStrNotTag ) { -+ Sizzle.filter( part, checkSet, true ); -+ } -+ }, -+ -+ ">": function( checkSet, part ) { -+ var elem, -+ isPartStr = typeof part === "string", -+ i = 0, -+ l = checkSet.length; -+ -+ if ( isPartStr && !rNonWord.test( part ) ) { -+ part = part.toLowerCase(); -+ -+ for ( ; i < l; i++ ) { -+ elem = checkSet[i]; -+ -+ if ( elem ) { -+ var parent = elem.parentNode; -+ checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; -+ } -+ } -+ -+ } else { -+ for ( ; i < l; i++ ) { -+ elem = checkSet[i]; -+ -+ if ( elem ) { -+ checkSet[i] = isPartStr ? -+ elem.parentNode : -+ elem.parentNode === part; -+ } -+ } -+ -+ if ( isPartStr ) { -+ Sizzle.filter( part, checkSet, true ); -+ } -+ } -+ }, -+ -+ "": function(checkSet, part, isXML){ -+ var nodeCheck, -+ doneName = done++, -+ checkFn = dirCheck; -+ -+ if ( typeof part === "string" && !rNonWord.test( part ) ) { -+ part = part.toLowerCase(); -+ nodeCheck = part; -+ checkFn = dirNodeCheck; -+ } -+ -+ checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); -+ }, -+ -+ "~": function( checkSet, part, isXML ) { -+ var nodeCheck, -+ doneName = done++, -+ checkFn = dirCheck; -+ -+ if ( typeof part === "string" && !rNonWord.test( part ) ) { -+ part = part.toLowerCase(); -+ nodeCheck = part; -+ checkFn = dirNodeCheck; -+ } -+ -+ checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); -+ } -+ }, -+ -+ find: { -+ ID: function( match, context, isXML ) { -+ if ( typeof context.getElementById !== "undefined" && !isXML ) { -+ var m = context.getElementById(match[1]); -+ // Check parentNode to catch when Blackberry 4.6 returns -+ // nodes that are no longer in the document #6963 -+ return m && m.parentNode ? [m] : []; -+ } -+ }, -+ -+ NAME: function( match, context ) { -+ if ( typeof context.getElementsByName !== "undefined" ) { -+ var ret = [], -+ results = context.getElementsByName( match[1] ); -+ -+ for ( var i = 0, l = results.length; i < l; i++ ) { -+ if ( results[i].getAttribute("name") === match[1] ) { -+ ret.push( results[i] ); -+ } -+ } -+ -+ return ret.length === 0 ? null : ret; -+ } -+ }, -+ -+ TAG: function( match, context ) { -+ if ( typeof context.getElementsByTagName !== "undefined" ) { -+ return context.getElementsByTagName( match[1] ); -+ } -+ } -+ }, -+ preFilter: { -+ CLASS: function( match, curLoop, inplace, result, not, isXML ) { -+ match = " " + match[1].replace( rBackslash, "" ) + " "; -+ -+ if ( isXML ) { -+ return match; -+ } -+ -+ for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { -+ if ( elem ) { -+ if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { -+ if ( !inplace ) { -+ result.push( elem ); -+ } -+ -+ } else if ( inplace ) { -+ curLoop[i] = false; -+ } -+ } -+ } -+ -+ return false; -+ }, -+ -+ ID: function( match ) { -+ return match[1].replace( rBackslash, "" ); -+ }, -+ -+ TAG: function( match, curLoop ) { -+ return match[1].replace( rBackslash, "" ).toLowerCase(); -+ }, -+ -+ CHILD: function( match ) { -+ if ( match[1] === "nth" ) { -+ if ( !match[2] ) { -+ Sizzle.error( match[0] ); -+ } -+ -+ match[2] = match[2].replace(/^\+|\s*/g, ''); -+ -+ // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' -+ var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( -+ match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || -+ !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); -+ -+ // calculate the numbers (first)n+(last) including if they are negative -+ match[2] = (test[1] + (test[2] || 1)) - 0; -+ match[3] = test[3] - 0; -+ } -+ else if ( match[2] ) { -+ Sizzle.error( match[0] ); -+ } -+ -+ // TODO: Move to normal caching system -+ match[0] = done++; -+ -+ return match; -+ }, -+ -+ ATTR: function( match, curLoop, inplace, result, not, isXML ) { -+ var name = match[1] = match[1].replace( rBackslash, "" ); -+ -+ if ( !isXML && Expr.attrMap[name] ) { -+ match[1] = Expr.attrMap[name]; -+ } -+ -+ // Handle if an un-quoted value was used -+ match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); -+ -+ if ( match[2] === "~=" ) { -+ match[4] = " " + match[4] + " "; -+ } -+ -+ return match; -+ }, -+ -+ PSEUDO: function( match, curLoop, inplace, result, not ) { -+ if ( match[1] === "not" ) { -+ // If we're dealing with a complex expression, or a simple one -+ if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { -+ match[3] = Sizzle(match[3], null, null, curLoop); -+ -+ } else { -+ var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); -+ -+ if ( !inplace ) { -+ result.push.apply( result, ret ); -+ } -+ -+ return false; -+ } -+ -+ } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { -+ return true; -+ } -+ -+ return match; -+ }, -+ -+ POS: function( match ) { -+ match.unshift( true ); -+ -+ return match; -+ } -+ }, -+ -+ filters: { -+ enabled: function( elem ) { -+ return elem.disabled === false && elem.type !== "hidden"; -+ }, -+ -+ disabled: function( elem ) { -+ return elem.disabled === true; -+ }, -+ -+ checked: function( elem ) { -+ return elem.checked === true; -+ }, -+ -+ selected: function( elem ) { -+ // Accessing this property makes selected-by-default -+ // options in Safari work properly -+ if ( elem.parentNode ) { -+ elem.parentNode.selectedIndex; -+ } -+ -+ return elem.selected === true; -+ }, -+ -+ parent: function( elem ) { -+ return !!elem.firstChild; -+ }, -+ -+ empty: function( elem ) { -+ return !elem.firstChild; -+ }, -+ -+ has: function( elem, i, match ) { -+ return !!Sizzle( match[3], elem ).length; -+ }, -+ -+ header: function( elem ) { -+ return (/h\d/i).test( elem.nodeName ); -+ }, -+ -+ text: function( elem ) { -+ var attr = elem.getAttribute( "type" ), type = elem.type; -+ // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) -+ // use getAttribute instead to test this case -+ return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); -+ }, -+ -+ radio: function( elem ) { -+ return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; -+ }, -+ -+ checkbox: function( elem ) { -+ return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; -+ }, -+ -+ file: function( elem ) { -+ return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; -+ }, -+ -+ password: function( elem ) { -+ return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; -+ }, -+ -+ submit: function( elem ) { -+ var name = elem.nodeName.toLowerCase(); -+ return (name === "input" || name === "button") && "submit" === elem.type; -+ }, -+ -+ image: function( elem ) { -+ return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; -+ }, -+ -+ reset: function( elem ) { -+ var name = elem.nodeName.toLowerCase(); -+ return (name === "input" || name === "button") && "reset" === elem.type; -+ }, -+ -+ button: function( elem ) { -+ var name = elem.nodeName.toLowerCase(); -+ return name === "input" && "button" === elem.type || name === "button"; -+ }, -+ -+ input: function( elem ) { -+ return (/input|select|textarea|button/i).test( elem.nodeName ); -+ }, -+ -+ focus: function( elem ) { -+ return elem === elem.ownerDocument.activeElement; -+ } -+ }, -+ setFilters: { -+ first: function( elem, i ) { -+ return i === 0; -+ }, -+ -+ last: function( elem, i, match, array ) { -+ return i === array.length - 1; -+ }, -+ -+ even: function( elem, i ) { -+ return i % 2 === 0; -+ }, -+ -+ odd: function( elem, i ) { -+ return i % 2 === 1; -+ }, -+ -+ lt: function( elem, i, match ) { -+ return i < match[3] - 0; -+ }, -+ -+ gt: function( elem, i, match ) { -+ return i > match[3] - 0; -+ }, -+ -+ nth: function( elem, i, match ) { -+ return match[3] - 0 === i; -+ }, -+ -+ eq: function( elem, i, match ) { -+ return match[3] - 0 === i; -+ } -+ }, -+ filter: { -+ PSEUDO: function( elem, match, i, array ) { -+ var name = match[1], -+ filter = Expr.filters[ name ]; -+ -+ if ( filter ) { -+ return filter( elem, i, match, array ); -+ -+ } else if ( name === "contains" ) { -+ return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; -+ -+ } else if ( name === "not" ) { -+ var not = match[3]; -+ -+ for ( var j = 0, l = not.length; j < l; j++ ) { -+ if ( not[j] === elem ) { -+ return false; -+ } -+ } -+ -+ return true; -+ -+ } else { -+ Sizzle.error( name ); -+ } -+ }, -+ -+ CHILD: function( elem, match ) { -+ var first, last, -+ doneName, parent, cache, -+ count, diff, -+ type = match[1], -+ node = elem; -+ -+ switch ( type ) { -+ case "only": -+ case "first": -+ while ( (node = node.previousSibling) ) { -+ if ( node.nodeType === 1 ) { -+ return false; -+ } -+ } -+ -+ if ( type === "first" ) { -+ return true; -+ } -+ -+ node = elem; -+ -+ /* falls through */ -+ case "last": -+ while ( (node = node.nextSibling) ) { -+ if ( node.nodeType === 1 ) { -+ return false; -+ } -+ } -+ -+ return true; -+ -+ case "nth": -+ first = match[2]; -+ last = match[3]; -+ -+ if ( first === 1 && last === 0 ) { -+ return true; -+ } -+ -+ doneName = match[0]; -+ parent = elem.parentNode; -+ -+ if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) { -+ count = 0; -+ -+ for ( node = parent.firstChild; node; node = node.nextSibling ) { -+ if ( node.nodeType === 1 ) { -+ node.nodeIndex = ++count; -+ } -+ } -+ -+ parent[ expando ] = doneName; -+ } -+ -+ diff = elem.nodeIndex - last; -+ -+ if ( first === 0 ) { -+ return diff === 0; -+ -+ } else { -+ return ( diff % first === 0 && diff / first >= 0 ); -+ } -+ } -+ }, -+ -+ ID: function( elem, match ) { -+ return elem.nodeType === 1 && elem.getAttribute("id") === match; -+ }, -+ -+ TAG: function( elem, match ) { -+ return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match; -+ }, -+ -+ CLASS: function( elem, match ) { -+ return (" " + (elem.className || elem.getAttribute("class")) + " ") -+ .indexOf( match ) > -1; -+ }, -+ -+ ATTR: function( elem, match ) { -+ var name = match[1], -+ result = Sizzle.attr ? -+ Sizzle.attr( elem, name ) : -+ Expr.attrHandle[ name ] ? -+ Expr.attrHandle[ name ]( elem ) : -+ elem[ name ] != null ? -+ elem[ name ] : -+ elem.getAttribute( name ), -+ value = result + "", -+ type = match[2], -+ check = match[4]; -+ -+ return result == null ? -+ type === "!=" : -+ !type && Sizzle.attr ? -+ result != null : -+ type === "=" ? -+ value === check : -+ type === "*=" ? -+ value.indexOf(check) >= 0 : -+ type === "~=" ? -+ (" " + value + " ").indexOf(check) >= 0 : -+ !check ? -+ value && result !== false : -+ type === "!=" ? -+ value !== check : -+ type === "^=" ? -+ value.indexOf(check) === 0 : -+ type === "$=" ? -+ value.substr(value.length - check.length) === check : -+ type === "|=" ? -+ value === check || value.substr(0, check.length + 1) === check + "-" : -+ false; -+ }, -+ -+ POS: function( elem, match, i, array ) { -+ var name = match[2], -+ filter = Expr.setFilters[ name ]; -+ -+ if ( filter ) { -+ return filter( elem, i, match, array ); -+ } -+ } -+ } -+}; -+ -+var origPOS = Expr.match.POS, -+ fescape = function(all, num){ -+ return "\\" + (num - 0 + 1); -+ }; -+ -+for ( var type in Expr.match ) { -+ Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); -+ Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); -+} -+// Expose origPOS -+// "global" as in regardless of relation to brackets/parens -+Expr.match.globalPOS = origPOS; -+ -+var makeArray = function( array, results ) { -+ array = Array.prototype.slice.call( array, 0 ); -+ -+ if ( results ) { -+ results.push.apply( results, array ); -+ return results; -+ } -+ -+ return array; -+}; -+ -+// Perform a simple check to determine if the browser is capable of -+// converting a NodeList to an array using builtin methods. -+// Also verifies that the returned array holds DOM nodes -+// (which is not the case in the Blackberry browser) -+try { -+ Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; -+ -+// Provide a fallback method if it does not work -+} catch( e ) { -+ makeArray = function( array, results ) { -+ var i = 0, -+ ret = results || []; -+ -+ if ( toString.call(array) === "[object Array]" ) { -+ Array.prototype.push.apply( ret, array ); -+ -+ } else { -+ if ( typeof array.length === "number" ) { -+ for ( var l = array.length; i < l; i++ ) { -+ ret.push( array[i] ); -+ } -+ -+ } else { -+ for ( ; array[i]; i++ ) { -+ ret.push( array[i] ); -+ } -+ } -+ } -+ -+ return ret; -+ }; -+} -+ -+var sortOrder, siblingCheck; -+ -+if ( document.documentElement.compareDocumentPosition ) { -+ sortOrder = function( a, b ) { -+ if ( a === b ) { -+ hasDuplicate = true; -+ return 0; -+ } -+ -+ if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { -+ return a.compareDocumentPosition ? -1 : 1; -+ } -+ -+ return a.compareDocumentPosition(b) & 4 ? -1 : 1; -+ }; -+ -+} else { -+ sortOrder = function( a, b ) { -+ // The nodes are identical, we can exit early -+ if ( a === b ) { -+ hasDuplicate = true; -+ return 0; -+ -+ // Fallback to using sourceIndex (in IE) if it's available on both nodes -+ } else if ( a.sourceIndex && b.sourceIndex ) { -+ return a.sourceIndex - b.sourceIndex; -+ } -+ -+ var al, bl, -+ ap = [], -+ bp = [], -+ aup = a.parentNode, -+ bup = b.parentNode, -+ cur = aup; -+ -+ // If the nodes are siblings (or identical) we can do a quick check -+ if ( aup === bup ) { -+ return siblingCheck( a, b ); -+ -+ // If no parents were found then the nodes are disconnected -+ } else if ( !aup ) { -+ return -1; -+ -+ } else if ( !bup ) { -+ return 1; -+ } -+ -+ // Otherwise they're somewhere else in the tree so we need -+ // to build up a full list of the parentNodes for comparison -+ while ( cur ) { -+ ap.unshift( cur ); -+ cur = cur.parentNode; -+ } -+ -+ cur = bup; -+ -+ while ( cur ) { -+ bp.unshift( cur ); -+ cur = cur.parentNode; -+ } -+ -+ al = ap.length; -+ bl = bp.length; -+ -+ // Start walking down the tree looking for a discrepancy -+ for ( var i = 0; i < al && i < bl; i++ ) { -+ if ( ap[i] !== bp[i] ) { -+ return siblingCheck( ap[i], bp[i] ); -+ } -+ } -+ -+ // We ended someplace up the tree so do a sibling check -+ return i === al ? -+ siblingCheck( a, bp[i], -1 ) : -+ siblingCheck( ap[i], b, 1 ); -+ }; -+ -+ siblingCheck = function( a, b, ret ) { -+ if ( a === b ) { -+ return ret; -+ } -+ -+ var cur = a.nextSibling; -+ -+ while ( cur ) { -+ if ( cur === b ) { -+ return -1; -+ } -+ -+ cur = cur.nextSibling; -+ } -+ -+ return 1; -+ }; -+} -+ -+// Check to see if the browser returns elements by name when -+// querying by getElementById (and provide a workaround) -+(function(){ -+ // We're going to inject a fake input element with a specified name -+ var form = document.createElement("div"), -+ id = "script" + (new Date()).getTime(), -+ root = document.documentElement; -+ -+ form.innerHTML = ""; -+ -+ // Inject it into the root element, check its status, and remove it quickly -+ root.insertBefore( form, root.firstChild ); -+ -+ // The workaround has to do additional checks after a getElementById -+ // Which slows things down for other browsers (hence the branching) -+ if ( document.getElementById( id ) ) { -+ Expr.find.ID = function( match, context, isXML ) { -+ if ( typeof context.getElementById !== "undefined" && !isXML ) { -+ var m = context.getElementById(match[1]); -+ -+ return m ? -+ m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? -+ [m] : -+ undefined : -+ []; -+ } -+ }; -+ -+ Expr.filter.ID = function( elem, match ) { -+ var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); -+ -+ return elem.nodeType === 1 && node && node.nodeValue === match; -+ }; -+ } -+ -+ root.removeChild( form ); -+ -+ // release memory in IE -+ root = form = null; -+})(); -+ -+(function(){ -+ // Check to see if the browser returns only elements -+ // when doing getElementsByTagName("*") -+ -+ // Create a fake element -+ var div = document.createElement("div"); -+ div.appendChild( document.createComment("") ); -+ -+ // Make sure no comments are found -+ if ( div.getElementsByTagName("*").length > 0 ) { -+ Expr.find.TAG = function( match, context ) { -+ var results = context.getElementsByTagName( match[1] ); -+ -+ // Filter out possible comments -+ if ( match[1] === "*" ) { -+ var tmp = []; -+ -+ for ( var i = 0; results[i]; i++ ) { -+ if ( results[i].nodeType === 1 ) { -+ tmp.push( results[i] ); -+ } -+ } -+ -+ results = tmp; -+ } -+ -+ return results; -+ }; -+ } -+ -+ // Check to see if an attribute returns normalized href attributes -+ div.innerHTML = ""; -+ -+ if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && -+ div.firstChild.getAttribute("href") !== "#" ) { -+ -+ Expr.attrHandle.href = function( elem ) { -+ return elem.getAttribute( "href", 2 ); -+ }; -+ } -+ -+ // release memory in IE -+ div = null; -+})(); -+ -+if ( document.querySelectorAll ) { -+ (function(){ -+ var oldSizzle = Sizzle, -+ div = document.createElement("div"), -+ id = "__sizzle__"; -+ -+ div.innerHTML = "

"; -+ -+ // Safari can't handle uppercase or unicode characters when -+ // in quirks mode. -+ if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { -+ return; -+ } -+ -+ Sizzle = function( query, context, extra, seed ) { -+ context = context || document; -+ -+ // Only use querySelectorAll on non-XML documents -+ // (ID selectors don't work in non-HTML documents) -+ if ( !seed && !Sizzle.isXML(context) ) { -+ // See if we find a selector to speed up -+ var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); -+ -+ if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { -+ // Speed-up: Sizzle("TAG") -+ if ( match[1] ) { -+ return makeArray( context.getElementsByTagName( query ), extra ); -+ -+ // Speed-up: Sizzle(".CLASS") -+ } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { -+ return makeArray( context.getElementsByClassName( match[2] ), extra ); -+ } -+ } -+ -+ if ( context.nodeType === 9 ) { -+ // Speed-up: Sizzle("body") -+ // The body element only exists once, optimize finding it -+ if ( query === "body" && context.body ) { -+ return makeArray( [ context.body ], extra ); -+ -+ // Speed-up: Sizzle("#ID") -+ } else if ( match && match[3] ) { -+ var elem = context.getElementById( match[3] ); -+ -+ // Check parentNode to catch when Blackberry 4.6 returns -+ // nodes that are no longer in the document #6963 -+ if ( elem && elem.parentNode ) { -+ // Handle the case where IE and Opera return items -+ // by name instead of ID -+ if ( elem.id === match[3] ) { -+ return makeArray( [ elem ], extra ); -+ } -+ -+ } else { -+ return makeArray( [], extra ); -+ } -+ } -+ -+ try { -+ return makeArray( context.querySelectorAll(query), extra ); -+ } catch(qsaError) {} -+ -+ // qSA works strangely on Element-rooted queries -+ // We can work around this by specifying an extra ID on the root -+ // and working up from there (Thanks to Andrew Dupont for the technique) -+ // IE 8 doesn't work on object elements -+ } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { -+ var oldContext = context, -+ old = context.getAttribute( "id" ), -+ nid = old || id, -+ hasParent = context.parentNode, -+ relativeHierarchySelector = /^\s*[+~]/.test( query ); -+ -+ if ( !old ) { -+ context.setAttribute( "id", nid ); -+ } else { -+ nid = nid.replace( /'/g, "\\$&" ); -+ } -+ if ( relativeHierarchySelector && hasParent ) { -+ context = context.parentNode; -+ } -+ -+ try { -+ if ( !relativeHierarchySelector || hasParent ) { -+ return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); -+ } -+ -+ } catch(pseudoError) { -+ } finally { -+ if ( !old ) { -+ oldContext.removeAttribute( "id" ); -+ } -+ } -+ } -+ } -+ -+ return oldSizzle(query, context, extra, seed); -+ }; -+ -+ for ( var prop in oldSizzle ) { -+ Sizzle[ prop ] = oldSizzle[ prop ]; -+ } -+ -+ // release memory in IE -+ div = null; -+ })(); -+} -+ -+(function(){ -+ var html = document.documentElement, -+ matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; -+ -+ if ( matches ) { -+ // Check to see if it's possible to do matchesSelector -+ // on a disconnected node (IE 9 fails this) -+ var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), -+ pseudoWorks = false; -+ -+ try { -+ // This should fail with an exception -+ // Gecko does not error, returns false instead -+ matches.call( document.documentElement, "[test!='']:sizzle" ); -+ -+ } catch( pseudoError ) { -+ pseudoWorks = true; -+ } -+ -+ Sizzle.matchesSelector = function( node, expr ) { -+ // Make sure that attribute selectors are quoted -+ expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); -+ -+ if ( !Sizzle.isXML( node ) ) { -+ try { -+ if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { -+ var ret = matches.call( node, expr ); -+ -+ // IE 9's matchesSelector returns false on disconnected nodes -+ if ( ret || !disconnectedMatch || -+ // As well, disconnected nodes are said to be in a document -+ // fragment in IE 9, so check for that -+ node.document && node.document.nodeType !== 11 ) { -+ return ret; -+ } -+ } -+ } catch(e) {} -+ } -+ -+ return Sizzle(expr, null, null, [node]).length > 0; -+ }; -+ } -+})(); -+ -+(function(){ -+ var div = document.createElement("div"); -+ -+ div.innerHTML = "
"; -+ -+ // Opera can't find a second classname (in 9.6) -+ // Also, make sure that getElementsByClassName actually exists -+ if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { -+ return; -+ } -+ -+ // Safari caches class attributes, doesn't catch changes (in 3.2) -+ div.lastChild.className = "e"; -+ -+ if ( div.getElementsByClassName("e").length === 1 ) { -+ return; -+ } -+ -+ Expr.order.splice(1, 0, "CLASS"); -+ Expr.find.CLASS = function( match, context, isXML ) { -+ if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { -+ return context.getElementsByClassName(match[1]); -+ } -+ }; -+ -+ // release memory in IE -+ div = null; -+})(); -+ -+function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { -+ for ( var i = 0, l = checkSet.length; i < l; i++ ) { -+ var elem = checkSet[i]; -+ -+ if ( elem ) { -+ var match = false; -+ -+ elem = elem[dir]; -+ -+ while ( elem ) { -+ if ( elem[ expando ] === doneName ) { -+ match = checkSet[elem.sizset]; -+ break; -+ } -+ -+ if ( elem.nodeType === 1 && !isXML ){ -+ elem[ expando ] = doneName; -+ elem.sizset = i; -+ } -+ -+ if ( elem.nodeName.toLowerCase() === cur ) { -+ match = elem; -+ break; -+ } -+ -+ elem = elem[dir]; -+ } -+ -+ checkSet[i] = match; -+ } -+ } -+} -+ -+function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { -+ for ( var i = 0, l = checkSet.length; i < l; i++ ) { -+ var elem = checkSet[i]; -+ -+ if ( elem ) { -+ var match = false; -+ -+ elem = elem[dir]; -+ -+ while ( elem ) { -+ if ( elem[ expando ] === doneName ) { -+ match = checkSet[elem.sizset]; -+ break; -+ } -+ -+ if ( elem.nodeType === 1 ) { -+ if ( !isXML ) { -+ elem[ expando ] = doneName; -+ elem.sizset = i; -+ } -+ -+ if ( typeof cur !== "string" ) { -+ if ( elem === cur ) { -+ match = true; -+ break; -+ } -+ -+ } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { -+ match = elem; -+ break; -+ } -+ } -+ -+ elem = elem[dir]; -+ } -+ -+ checkSet[i] = match; -+ } -+ } -+} -+ -+if ( document.documentElement.contains ) { -+ Sizzle.contains = function( a, b ) { -+ return a !== b && (a.contains ? a.contains(b) : true); -+ }; -+ -+} else if ( document.documentElement.compareDocumentPosition ) { -+ Sizzle.contains = function( a, b ) { -+ return !!(a.compareDocumentPosition(b) & 16); -+ }; -+ -+} else { -+ Sizzle.contains = function() { -+ return false; -+ }; -+} -+ -+Sizzle.isXML = function( elem ) { -+ // documentElement is verified for cases where it doesn't yet exist -+ // (such as loading iframes in IE - #4833) -+ var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; -+ -+ return documentElement ? documentElement.nodeName !== "HTML" : false; -+}; -+ -+var posProcess = function( selector, context, seed ) { -+ var match, -+ tmpSet = [], -+ later = "", -+ root = context.nodeType ? [context] : context; -+ -+ // Position selectors must be done after the filter -+ // And so must :not(positional) so we move all PSEUDOs to the end -+ while ( (match = Expr.match.PSEUDO.exec( selector )) ) { -+ later += match[0]; -+ selector = selector.replace( Expr.match.PSEUDO, "" ); -+ } -+ -+ selector = Expr.relative[selector] ? selector + "*" : selector; -+ -+ for ( var i = 0, l = root.length; i < l; i++ ) { -+ Sizzle( selector, root[i], tmpSet, seed ); -+ } -+ -+ return Sizzle.filter( later, tmpSet ); -+}; -+ -+// EXPOSE -+// Override sizzle attribute retrieval -+Sizzle.attr = jQuery.attr; -+Sizzle.selectors.attrMap = {}; -+jQuery.find = Sizzle; -+jQuery.expr = Sizzle.selectors; -+jQuery.expr[":"] = jQuery.expr.filters; -+jQuery.unique = Sizzle.uniqueSort; -+jQuery.text = Sizzle.getText; -+jQuery.isXMLDoc = Sizzle.isXML; -+jQuery.contains = Sizzle.contains; -+ -+ -+})(); -+ -+ -+var runtil = /Until$/, -+ rparentsprev = /^(?:parents|prevUntil|prevAll)/, -+ // Note: This RegExp should be improved, or likely pulled from Sizzle -+ rmultiselector = /,/, -+ isSimple = /^.[^:#\[\.,]*$/, -+ slice = Array.prototype.slice, -+ POS = jQuery.expr.match.globalPOS, -+ // methods guaranteed to produce a unique set when starting from a unique set -+ guaranteedUnique = { -+ children: true, -+ contents: true, -+ next: true, -+ prev: true -+ }; -+ -+jQuery.fn.extend({ -+ find: function( selector ) { -+ var self = this, -+ i, l; -+ -+ if ( typeof selector !== "string" ) { -+ return jQuery( selector ).filter(function() { -+ for ( i = 0, l = self.length; i < l; i++ ) { -+ if ( jQuery.contains( self[ i ], this ) ) { -+ return true; -+ } -+ } -+ }); -+ } -+ -+ var ret = this.pushStack( "", "find", selector ), -+ length, n, r; -+ -+ for ( i = 0, l = this.length; i < l; i++ ) { -+ length = ret.length; -+ jQuery.find( selector, this[i], ret ); -+ -+ if ( i > 0 ) { -+ // Make sure that the results are unique -+ for ( n = length; n < ret.length; n++ ) { -+ for ( r = 0; r < length; r++ ) { -+ if ( ret[r] === ret[n] ) { -+ ret.splice(n--, 1); -+ break; -+ } -+ } -+ } -+ } -+ } -+ -+ return ret; -+ }, -+ -+ has: function( target ) { -+ var targets = jQuery( target ); -+ return this.filter(function() { -+ for ( var i = 0, l = targets.length; i < l; i++ ) { -+ if ( jQuery.contains( this, targets[i] ) ) { -+ return true; -+ } -+ } -+ }); -+ }, -+ -+ not: function( selector ) { -+ return this.pushStack( winnow(this, selector, false), "not", selector); -+ }, -+ -+ filter: function( selector ) { -+ return this.pushStack( winnow(this, selector, true), "filter", selector ); -+ }, -+ -+ is: function( selector ) { -+ return !!selector && ( -+ typeof selector === "string" ? -+ // If this is a positional selector, check membership in the returned set -+ // so $("p:first").is("p:last") won't return true for a doc with two "p". -+ POS.test( selector ) ? -+ jQuery( selector, this.context ).index( this[0] ) >= 0 : -+ jQuery.filter( selector, this ).length > 0 : -+ this.filter( selector ).length > 0 ); -+ }, -+ -+ closest: function( selectors, context ) { -+ var ret = [], i, l, cur = this[0]; -+ -+ // Array (deprecated as of jQuery 1.7) -+ if ( jQuery.isArray( selectors ) ) { -+ var level = 1; -+ -+ while ( cur && cur.ownerDocument && cur !== context ) { -+ for ( i = 0; i < selectors.length; i++ ) { -+ -+ if ( jQuery( cur ).is( selectors[ i ] ) ) { -+ ret.push({ selector: selectors[ i ], elem: cur, level: level }); -+ } -+ } -+ -+ cur = cur.parentNode; -+ level++; -+ } -+ -+ return ret; -+ } -+ -+ // String -+ var pos = POS.test( selectors ) || typeof selectors !== "string" ? -+ jQuery( selectors, context || this.context ) : -+ 0; -+ -+ for ( i = 0, l = this.length; i < l; i++ ) { -+ cur = this[i]; -+ -+ while ( cur ) { -+ if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { -+ ret.push( cur ); -+ break; -+ -+ } else { -+ cur = cur.parentNode; -+ if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { -+ break; -+ } -+ } -+ } -+ } -+ -+ ret = ret.length > 1 ? jQuery.unique( ret ) : ret; -+ -+ return this.pushStack( ret, "closest", selectors ); -+ }, -+ -+ // Determine the position of an element within -+ // the matched set of elements -+ index: function( elem ) { -+ -+ // No argument, return index in parent -+ if ( !elem ) { -+ return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; -+ } -+ -+ // index in selector -+ if ( typeof elem === "string" ) { -+ return jQuery.inArray( this[0], jQuery( elem ) ); -+ } -+ -+ // Locate the position of the desired element -+ return jQuery.inArray( -+ // If it receives a jQuery object, the first element is used -+ elem.jquery ? elem[0] : elem, this ); -+ }, -+ -+ add: function( selector, context ) { -+ var set = typeof selector === "string" ? -+ jQuery( selector, context ) : -+ jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), -+ all = jQuery.merge( this.get(), set ); -+ -+ return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? -+ all : -+ jQuery.unique( all ) ); -+ }, -+ -+ andSelf: function() { -+ return this.add( this.prevObject ); -+ } -+}); -+ -+// A painfully simple check to see if an element is disconnected -+// from a document (should be improved, where feasible). -+function isDisconnected( node ) { -+ return !node || !node.parentNode || node.parentNode.nodeType === 11; -+} -+ -+jQuery.each({ -+ parent: function( elem ) { -+ var parent = elem.parentNode; -+ return parent && parent.nodeType !== 11 ? parent : null; -+ }, -+ parents: function( elem ) { -+ return jQuery.dir( elem, "parentNode" ); -+ }, -+ parentsUntil: function( elem, i, until ) { -+ return jQuery.dir( elem, "parentNode", until ); -+ }, -+ next: function( elem ) { -+ return jQuery.nth( elem, 2, "nextSibling" ); -+ }, -+ prev: function( elem ) { -+ return jQuery.nth( elem, 2, "previousSibling" ); -+ }, -+ nextAll: function( elem ) { -+ return jQuery.dir( elem, "nextSibling" ); -+ }, -+ prevAll: function( elem ) { -+ return jQuery.dir( elem, "previousSibling" ); -+ }, -+ nextUntil: function( elem, i, until ) { -+ return jQuery.dir( elem, "nextSibling", until ); -+ }, -+ prevUntil: function( elem, i, until ) { -+ return jQuery.dir( elem, "previousSibling", until ); -+ }, -+ siblings: function( elem ) { -+ return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); -+ }, -+ children: function( elem ) { -+ return jQuery.sibling( elem.firstChild ); -+ }, -+ contents: function( elem ) { -+ return jQuery.nodeName( elem, "iframe" ) ? -+ elem.contentDocument || elem.contentWindow.document : -+ jQuery.makeArray( elem.childNodes ); -+ } -+}, function( name, fn ) { -+ jQuery.fn[ name ] = function( until, selector ) { -+ var ret = jQuery.map( this, fn, until ); -+ -+ if ( !runtil.test( name ) ) { -+ selector = until; -+ } -+ -+ if ( selector && typeof selector === "string" ) { -+ ret = jQuery.filter( selector, ret ); -+ } -+ -+ ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; -+ -+ if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { -+ ret = ret.reverse(); -+ } -+ -+ return this.pushStack( ret, name, slice.call( arguments ).join(",") ); -+ }; -+}); -+ -+jQuery.extend({ -+ filter: function( expr, elems, not ) { -+ if ( not ) { -+ expr = ":not(" + expr + ")"; -+ } -+ -+ return elems.length === 1 ? -+ jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : -+ jQuery.find.matches(expr, elems); -+ }, -+ -+ dir: function( elem, dir, until ) { -+ var matched = [], -+ cur = elem[ dir ]; -+ -+ while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { -+ if ( cur.nodeType === 1 ) { -+ matched.push( cur ); -+ } -+ cur = cur[dir]; -+ } -+ return matched; -+ }, -+ -+ nth: function( cur, result, dir, elem ) { -+ result = result || 1; -+ var num = 0; -+ -+ for ( ; cur; cur = cur[dir] ) { -+ if ( cur.nodeType === 1 && ++num === result ) { -+ break; -+ } -+ } -+ -+ return cur; -+ }, -+ -+ sibling: function( n, elem ) { -+ var r = []; -+ -+ for ( ; n; n = n.nextSibling ) { -+ if ( n.nodeType === 1 && n !== elem ) { -+ r.push( n ); -+ } -+ } -+ -+ return r; -+ } -+}); -+ -+// Implement the identical functionality for filter and not -+function winnow( elements, qualifier, keep ) { -+ -+ // Can't pass null or undefined to indexOf in Firefox 4 -+ // Set to 0 to skip string check -+ qualifier = qualifier || 0; -+ -+ if ( jQuery.isFunction( qualifier ) ) { -+ return jQuery.grep(elements, function( elem, i ) { -+ var retVal = !!qualifier.call( elem, i, elem ); -+ return retVal === keep; -+ }); -+ -+ } else if ( qualifier.nodeType ) { -+ return jQuery.grep(elements, function( elem, i ) { -+ return ( elem === qualifier ) === keep; -+ }); -+ -+ } else if ( typeof qualifier === "string" ) { -+ var filtered = jQuery.grep(elements, function( elem ) { -+ return elem.nodeType === 1; -+ }); -+ -+ if ( isSimple.test( qualifier ) ) { -+ return jQuery.filter(qualifier, filtered, !keep); -+ } else { -+ qualifier = jQuery.filter( qualifier, filtered ); -+ } -+ } -+ -+ return jQuery.grep(elements, function( elem, i ) { -+ return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; -+ }); -+} -+ -+ -+ -+ -+function createSafeFragment( document ) { -+ var list = nodeNames.split( "|" ), -+ safeFrag = document.createDocumentFragment(); -+ -+ if ( safeFrag.createElement ) { -+ while ( list.length ) { -+ safeFrag.createElement( -+ list.pop() -+ ); -+ } -+ } -+ return safeFrag; -+} -+ -+var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + -+ "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", -+ rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, -+ rleadingWhitespace = /^\s+/, -+ rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, -+ rtagName = /<([\w:]+)/, -+ rtbody = /]", "i"), -+ // checked="checked" or checked -+ rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, -+ rscriptType = /\/(java|ecma)script/i, -+ rcleanScript = /^\s*", "" ], -+ legend: [ 1, "
", "
" ], -+ thead: [ 1, "", "
" ], -+ tr: [ 2, "", "
" ], -+ td: [ 3, "", "
" ], -+ col: [ 2, "", "
" ], -+ area: [ 1, "", "" ], -+ _default: [ 0, "", "" ] -+ }, -+ safeFragment = createSafeFragment( document ); -+ -+wrapMap.optgroup = wrapMap.option; -+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -+wrapMap.th = wrapMap.td; -+ -+// IE can't serialize and -+ -+ -+ -+ -+ -+ -+ -+ -+
-+
-+
-+
-+ -+ -+

Index

-+ -+
-+ -+
-+ -+ -+
-+
-+
-+
-+
-+ -+ -+ -+ -+ -+
-+
-+
-+
-+ -+ -+ -+ -\ No newline at end of file -diff --git a/webhub/_build/html/objects.inv b/webhub/_build/html/objects.inv -new file mode 100644 -index 0000000..5c344c4 -Binary files /dev/null and b/webhub/_build/html/objects.inv differ -diff --git a/webhub/_build/html/search.html b/webhub/_build/html/search.html -new file mode 100644 -index 0000000..5076d44 ---- /dev/null -+++ b/webhub/_build/html/search.html -@@ -0,0 +1,99 @@ -+ -+ -+ -+ -+ -+ -+ -+ Search — systerspcweb 2.7.6 documentation -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
-+
-+
-+
-+ -+

Search

-+
-+ -+

-+ Please activate JavaScript to enable the search -+ functionality. -+

-+
-+

-+ From here you can search these documents. Enter your search -+ words into the box below and click "search". Note that the search -+ function will automatically search for all of the words. Pages -+ containing fewer words won't appear in the result list. -+

-+
-+ -+ -+ -+
-+ -+
-+ -+
-+ -+
-+
-+
-+
-+
-+
-+
-+
-+
-+ -+ -+ -+ -\ No newline at end of file -diff --git a/webhub/_build/html/searchindex.js b/webhub/_build/html/searchindex.js -new file mode 100644 -index 0000000..387abf3 ---- /dev/null -+++ b/webhub/_build/html/searchindex.js -@@ -0,0 +1 @@ -+Search.setIndex({envversion:42,terms:{content:0,index:0,modul:0,search:0,page:0},objtypes:{},objnames:{},filenames:["systerspcweb"],titles:["Welcome to systerspcweb’s documentation!"],objects:{},titleterms:{systerspcweb:0,document:0,welcom:0,indic:0,tabl:0}}) -\ No newline at end of file -diff --git a/webhub/_build/html/systerspcweb.html b/webhub/_build/html/systerspcweb.html -new file mode 100644 -index 0000000..f41aed1 ---- /dev/null -+++ b/webhub/_build/html/systerspcweb.html -@@ -0,0 +1,109 @@ -+ -+ -+ -+ -+ -+ -+ -+ Welcome to systerspcweb’s documentation! — systerspcweb 2.7.6 documentation -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
-+
-+
-+
-+ -+
-+

Welcome to systerspcweb’s documentation!

-+

Contents:

-+
-+
    -+
-+
-+
-+
-+

Indices and tables

-+ -+
-+ -+ -+
-+
-+
-+
-+
-+

Table Of Contents

-+ -+ -+

This Page

-+ -+ -+ -+
-+
-+
-+
-+ -+ -+ -+ -\ No newline at end of file -diff --git a/webhub/conf.py b/webhub/conf.py -new file mode 100644 -index 0000000..4f5a1cd ---- /dev/null -+++ b/webhub/conf.py -@@ -0,0 +1,263 @@ -+# -*- coding: utf-8 -*- -+# -+# systerspcweb documentation build configuration file, created by -+# sphinx-quickstart on Wed Aug 13 20:07:49 2014. -+# -+# This file is execfile()d with the current directory set to its -+# containing dir. -+# -+# Note that not all possible configuration values are present in this -+# autogenerated file. -+# -+# All configuration values have a default; values that are commented out -+# serve to show the default. -+ -+import sys -+import os -+ -+sys.path.append('/home/rani/vdapp/webhub') -+ -+ -+# If extensions (or modules to document with autodoc) are in another directory, -+# add these directories to sys.path here. If the directory is relative to the -+# documentation root, use os.path.abspath to make it absolute, like shown here. -+#sys.path.insert(0, os.path.abspath('.')) -+ -+# -- General configuration ------------------------------------------------ -+ -+# If your documentation needs a minimal Sphinx version, state it here. -+#needs_sphinx = '1.0' -+ -+# Add any Sphinx extension module names here, as strings. They can be -+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -+# ones. -+extensions = [ -+ 'sphinx.ext.autodoc', -+] -+ -+# Add any paths that contain templates here, relative to this directory. -+templates_path = ['_templates'] -+ -+# The suffix of source filenames. -+source_suffix = '.txt' -+ -+# The encoding of source files. -+#source_encoding = 'utf-8-sig' -+ -+# The master toctree document. -+master_doc = 'systerspcweb' -+ -+# General information about the project. -+project = u'systerspcweb' -+copyright = u'2014, vaibhavi, rani' -+ -+# The version info for the project you're documenting, acts as replacement for -+# |version| and |release|, also used in various other places throughout the -+# built documents. -+# -+# The short X.Y version. -+version = '2.7' -+# The full version, including alpha/beta/rc tags. -+release = '2.7.6' -+ -+# The language for content autogenerated by Sphinx. Refer to documentation -+# for a list of supported languages. -+#language = None -+ -+# There are two options for replacing |today|: either, you set today to some -+# non-false value, then it is used: -+#today = '' -+# Else, today_fmt is used as the format for a strftime call. -+#today_fmt = '%B %d, %Y' -+ -+# List of patterns, relative to source directory, that match files and -+# directories to ignore when looking for source files. -+exclude_patterns = ['_build'] -+ -+# The reST default role (used for this markup: `text`) to use for all -+# documents. -+#default_role = None -+ -+# If true, '()' will be appended to :func: etc. cross-reference text. -+#add_function_parentheses = True -+ -+# If true, the current module name will be prepended to all description -+# unit titles (such as .. function::). -+#add_module_names = True -+ -+# If true, sectionauthor and moduleauthor directives will be shown in the -+# output. They are ignored by default. -+#show_authors = False -+ -+# The name of the Pygments (syntax highlighting) style to use. -+pygments_style = 'sphinx' -+ -+# A list of ignored prefixes for module index sorting. -+#modindex_common_prefix = [] -+ -+# If true, keep warnings as "system message" paragraphs in the built documents. -+#keep_warnings = False -+ -+ -+# -- Options for HTML output ---------------------------------------------- -+ -+# The theme to use for HTML and HTML Help pages. See the documentation for -+# a list of builtin themes. -+html_theme = 'default' -+ -+# Theme options are theme-specific and customize the look and feel of a theme -+# further. For a list of options available for each theme, see the -+# documentation. -+#html_theme_options = {} -+ -+# Add any paths that contain custom themes here, relative to this directory. -+#html_theme_path = [] -+ -+# The name for this set of Sphinx documents. If None, it defaults to -+# " v documentation". -+#html_title = None -+ -+# A shorter title for the navigation bar. Default is the same as html_title. -+#html_short_title = None -+ -+# The name of an image file (relative to this directory) to place at the top -+# of the sidebar. -+#html_logo = None -+ -+# The name of an image file (within the static path) to use as favicon of the -+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -+# pixels large. -+#html_favicon = None -+ -+# Add any paths that contain custom static files (such as style sheets) here, -+# relative to this directory. They are copied after the builtin static files, -+# so a file named "default.css" will overwrite the builtin "default.css". -+html_static_path = ['_static'] -+ -+# Add any extra paths that contain custom files (such as robots.txt or -+# .htaccess) here, relative to this directory. These files are copied -+# directly to the root of the documentation. -+#html_extra_path = [] -+ -+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -+# using the given strftime format. -+#html_last_updated_fmt = '%b %d, %Y' -+ -+# If true, SmartyPants will be used to convert quotes and dashes to -+# typographically correct entities. -+#html_use_smartypants = True -+ -+# Custom sidebar templates, maps document names to template names. -+#html_sidebars = {} -+ -+# Additional templates that should be rendered to pages, maps page names to -+# template names. -+#html_additional_pages = {} -+ -+# If false, no module index is generated. -+#html_domain_indices = True -+ -+# If false, no index is generated. -+#html_use_index = True -+ -+# If true, the index is split into individual pages for each letter. -+#html_split_index = False -+ -+# If true, links to the reST sources are added to the pages. -+#html_show_sourcelink = True -+ -+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -+#html_show_sphinx = True -+ -+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -+#html_show_copyright = True -+ -+# If true, an OpenSearch description file will be output, and all pages will -+# contain a tag referring to it. The value of this option must be the -+# base URL from which the finished HTML is served. -+#html_use_opensearch = '' -+ -+# This is the file name suffix for HTML files (e.g. ".xhtml"). -+#html_file_suffix = None -+ -+# Output file base name for HTML help builder. -+htmlhelp_basename = 'systerspcwebdoc' -+ -+ -+# -- Options for LaTeX output --------------------------------------------- -+ -+latex_elements = { -+# The paper size ('letterpaper' or 'a4paper'). -+#'papersize': 'letterpaper', -+ -+# The font size ('10pt', '11pt' or '12pt'). -+#'pointsize': '10pt', -+ -+# Additional stuff for the LaTeX preamble. -+#'preamble': '', -+} -+ -+# Grouping the document tree into LaTeX files. List of tuples -+# (source start file, target name, title, -+# author, documentclass [howto, manual, or own class]). -+latex_documents = [ -+ ('systerspcweb', 'systerspcweb.tex', u'systerspcweb Documentation', -+ u'vaibhavi, rani', 'manual'), -+] -+ -+# The name of an image file (relative to this directory) to place at the top of -+# the title page. -+#latex_logo = None -+ -+# For "manual" documents, if this is true, then toplevel headings are parts, -+# not chapters. -+#latex_use_parts = False -+ -+# If true, show page references after internal links. -+#latex_show_pagerefs = False -+ -+# If true, show URL addresses after external links. -+#latex_show_urls = False -+ -+# Documents to append as an appendix to all manuals. -+#latex_appendices = [] -+ -+# If false, no module index is generated. -+#latex_domain_indices = True -+ -+ -+# -- Options for manual page output --------------------------------------- -+ -+# One entry per manual page. List of tuples -+# (source start file, name, description, authors, manual section). -+man_pages = [ -+ ('systerspcweb', 'systerspcweb', u'systerspcweb Documentation', -+ [u'vaibhavi, rani'], 1) -+] -+ -+# If true, show URL addresses after external links. -+#man_show_urls = False -+ -+ -+# -- Options for Texinfo output ------------------------------------------- -+ -+# Grouping the document tree into Texinfo files. List of tuples -+# (source start file, target name, title, author, -+# dir menu entry, description, category) -+texinfo_documents = [ -+ ('systerspcweb', 'systerspcweb', u'systerspcweb Documentation', -+ u'vaibhavi, rani', 'systerspcweb', 'One line description of project.', -+ 'Miscellaneous'), -+] -+ -+# Documents to append as an appendix to all manuals. -+#texinfo_appendices = [] -+ -+# If false, no module index is generated. -+#texinfo_domain_indices = True -+ -+# How to display URL addresses: 'footnote', 'no', or 'inline'. -+#texinfo_show_urls = 'footnote' -+ -+# If true, do not generate a @detailmenu in the "Top" node's menu. -+#texinfo_no_detailmenu = False -diff --git a/webhub/conf.py~ b/webhub/conf.py~ -new file mode 100644 -index 0000000..63d484c ---- /dev/null -+++ b/webhub/conf.py~ -@@ -0,0 +1,262 @@ -+# -*- coding: utf-8 -*- -+# -+# systerspcweb documentation build configuration file, created by -+# sphinx-quickstart on Wed Aug 13 20:07:49 2014. -+# -+# This file is execfile()d with the current directory set to its -+# containing dir. -+# -+# Note that not all possible configuration values are present in this -+# autogenerated file. -+# -+# All configuration values have a default; values that are commented out -+# serve to show the default. -+ -+import sys -+import os -+ -+sys.path.insert(0,"home\\rani\\vdapp\\webhub") -+ -+# If extensions (or modules to document with autodoc) are in another directory, -+# add these directories to sys.path here. If the directory is relative to the -+# documentation root, use os.path.abspath to make it absolute, like shown here. -+#sys.path.insert(0, os.path.abspath('.')) -+ -+# -- General configuration ------------------------------------------------ -+ -+# If your documentation needs a minimal Sphinx version, state it here. -+#needs_sphinx = '1.0' -+ -+# Add any Sphinx extension module names here, as strings. They can be -+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -+# ones. -+extensions = [ -+ 'sphinx.ext.autodoc', -+] -+ -+# Add any paths that contain templates here, relative to this directory. -+templates_path = ['_templates'] -+ -+# The suffix of source filenames. -+source_suffix = '.txt' -+ -+# The encoding of source files. -+#source_encoding = 'utf-8-sig' -+ -+# The master toctree document. -+master_doc = 'systerspcweb' -+ -+# General information about the project. -+project = u'systerspcweb' -+copyright = u'2014, vaibhavi, rani' -+ -+# The version info for the project you're documenting, acts as replacement for -+# |version| and |release|, also used in various other places throughout the -+# built documents. -+# -+# The short X.Y version. -+version = '2.7' -+# The full version, including alpha/beta/rc tags. -+release = '2.7.6' -+ -+# The language for content autogenerated by Sphinx. Refer to documentation -+# for a list of supported languages. -+#language = None -+ -+# There are two options for replacing |today|: either, you set today to some -+# non-false value, then it is used: -+#today = '' -+# Else, today_fmt is used as the format for a strftime call. -+#today_fmt = '%B %d, %Y' -+ -+# List of patterns, relative to source directory, that match files and -+# directories to ignore when looking for source files. -+exclude_patterns = ['_build'] -+ -+# The reST default role (used for this markup: `text`) to use for all -+# documents. -+#default_role = None -+ -+# If true, '()' will be appended to :func: etc. cross-reference text. -+#add_function_parentheses = True -+ -+# If true, the current module name will be prepended to all description -+# unit titles (such as .. function::). -+#add_module_names = True -+ -+# If true, sectionauthor and moduleauthor directives will be shown in the -+# output. They are ignored by default. -+#show_authors = False -+ -+# The name of the Pygments (syntax highlighting) style to use. -+pygments_style = 'sphinx' -+ -+# A list of ignored prefixes for module index sorting. -+#modindex_common_prefix = [] -+ -+# If true, keep warnings as "system message" paragraphs in the built documents. -+#keep_warnings = False -+ -+ -+# -- Options for HTML output ---------------------------------------------- -+ -+# The theme to use for HTML and HTML Help pages. See the documentation for -+# a list of builtin themes. -+html_theme = 'default' -+ -+# Theme options are theme-specific and customize the look and feel of a theme -+# further. For a list of options available for each theme, see the -+# documentation. -+#html_theme_options = {} -+ -+# Add any paths that contain custom themes here, relative to this directory. -+#html_theme_path = [] -+ -+# The name for this set of Sphinx documents. If None, it defaults to -+# " v documentation". -+#html_title = None -+ -+# A shorter title for the navigation bar. Default is the same as html_title. -+#html_short_title = None -+ -+# The name of an image file (relative to this directory) to place at the top -+# of the sidebar. -+#html_logo = None -+ -+# The name of an image file (within the static path) to use as favicon of the -+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -+# pixels large. -+#html_favicon = None -+ -+# Add any paths that contain custom static files (such as style sheets) here, -+# relative to this directory. They are copied after the builtin static files, -+# so a file named "default.css" will overwrite the builtin "default.css". -+html_static_path = ['_static'] -+ -+# Add any extra paths that contain custom files (such as robots.txt or -+# .htaccess) here, relative to this directory. These files are copied -+# directly to the root of the documentation. -+#html_extra_path = [] -+ -+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -+# using the given strftime format. -+#html_last_updated_fmt = '%b %d, %Y' -+ -+# If true, SmartyPants will be used to convert quotes and dashes to -+# typographically correct entities. -+#html_use_smartypants = True -+ -+# Custom sidebar templates, maps document names to template names. -+#html_sidebars = {} -+ -+# Additional templates that should be rendered to pages, maps page names to -+# template names. -+#html_additional_pages = {} -+ -+# If false, no module index is generated. -+#html_domain_indices = True -+ -+# If false, no index is generated. -+#html_use_index = True -+ -+# If true, the index is split into individual pages for each letter. -+#html_split_index = False -+ -+# If true, links to the reST sources are added to the pages. -+#html_show_sourcelink = True -+ -+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -+#html_show_sphinx = True -+ -+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -+#html_show_copyright = True -+ -+# If true, an OpenSearch description file will be output, and all pages will -+# contain a tag referring to it. The value of this option must be the -+# base URL from which the finished HTML is served. -+#html_use_opensearch = '' -+ -+# This is the file name suffix for HTML files (e.g. ".xhtml"). -+#html_file_suffix = None -+ -+# Output file base name for HTML help builder. -+htmlhelp_basename = 'systerspcwebdoc' -+ -+ -+# -- Options for LaTeX output --------------------------------------------- -+ -+latex_elements = { -+# The paper size ('letterpaper' or 'a4paper'). -+#'papersize': 'letterpaper', -+ -+# The font size ('10pt', '11pt' or '12pt'). -+#'pointsize': '10pt', -+ -+# Additional stuff for the LaTeX preamble. -+#'preamble': '', -+} -+ -+# Grouping the document tree into LaTeX files. List of tuples -+# (source start file, target name, title, -+# author, documentclass [howto, manual, or own class]). -+latex_documents = [ -+ ('systerspcweb', 'systerspcweb.tex', u'systerspcweb Documentation', -+ u'vaibhavi, rani', 'manual'), -+] -+ -+# The name of an image file (relative to this directory) to place at the top of -+# the title page. -+#latex_logo = None -+ -+# For "manual" documents, if this is true, then toplevel headings are parts, -+# not chapters. -+#latex_use_parts = False -+ -+# If true, show page references after internal links. -+#latex_show_pagerefs = False -+ -+# If true, show URL addresses after external links. -+#latex_show_urls = False -+ -+# Documents to append as an appendix to all manuals. -+#latex_appendices = [] -+ -+# If false, no module index is generated. -+#latex_domain_indices = True -+ -+ -+# -- Options for manual page output --------------------------------------- -+ -+# One entry per manual page. List of tuples -+# (source start file, name, description, authors, manual section). -+man_pages = [ -+ ('systerspcweb', 'systerspcweb', u'systerspcweb Documentation', -+ [u'vaibhavi, rani'], 1) -+] -+ -+# If true, show URL addresses after external links. -+#man_show_urls = False -+ -+ -+# -- Options for Texinfo output ------------------------------------------- -+ -+# Grouping the document tree into Texinfo files. List of tuples -+# (source start file, target name, title, author, -+# dir menu entry, description, category) -+texinfo_documents = [ -+ ('systerspcweb', 'systerspcweb', u'systerspcweb Documentation', -+ u'vaibhavi, rani', 'systerspcweb', 'One line description of project.', -+ 'Miscellaneous'), -+] -+ -+# Documents to append as an appendix to all manuals. -+#texinfo_appendices = [] -+ -+# If false, no module index is generated. -+#texinfo_domain_indices = True -+ -+# How to display URL addresses: 'footnote', 'no', or 'inline'. -+#texinfo_show_urls = 'footnote' -+ -+# If true, do not generate a @detailmenu in the "Top" node's menu. -+#texinfo_no_detailmenu = False -diff --git a/webhub/make.bat b/webhub/make.bat -new file mode 100644 -index 0000000..db50cfe ---- /dev/null -+++ b/webhub/make.bat -@@ -0,0 +1,242 @@ -+@ECHO OFF -+ -+REM Command file for Sphinx documentation -+ -+if "%SPHINXBUILD%" == "" ( -+ set SPHINXBUILD=sphinx-build -+) -+set BUILDDIR=_build -+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . -+set I18NSPHINXOPTS=%SPHINXOPTS% . -+if NOT "%PAPER%" == "" ( -+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% -+ set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% -+) -+ -+if "%1" == "" goto help -+ -+if "%1" == "help" ( -+ :help -+ echo.Please use `make ^` where ^ is one of -+ echo. html to make standalone HTML files -+ echo. dirhtml to make HTML files named index.html in directories -+ echo. singlehtml to make a single large HTML file -+ echo. pickle to make pickle files -+ echo. json to make JSON files -+ echo. htmlhelp to make HTML files and a HTML help project -+ echo. qthelp to make HTML files and a qthelp project -+ echo. devhelp to make HTML files and a Devhelp project -+ echo. epub to make an epub -+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter -+ echo. text to make text files -+ echo. man to make manual pages -+ echo. texinfo to make Texinfo files -+ echo. gettext to make PO message catalogs -+ echo. changes to make an overview over all changed/added/deprecated items -+ echo. xml to make Docutils-native XML files -+ echo. pseudoxml to make pseudoxml-XML files for display purposes -+ echo. linkcheck to check all external links for integrity -+ echo. doctest to run all doctests embedded in the documentation if enabled -+ goto end -+) -+ -+if "%1" == "clean" ( -+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i -+ del /q /s %BUILDDIR%\* -+ goto end -+) -+ -+ -+%SPHINXBUILD% 2> nul -+if errorlevel 9009 ( -+ echo. -+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx -+ echo.installed, then set the SPHINXBUILD environment variable to point -+ echo.to the full path of the 'sphinx-build' executable. Alternatively you -+ echo.may add the Sphinx directory to PATH. -+ echo. -+ echo.If you don't have Sphinx installed, grab it from -+ echo.http://sphinx-doc.org/ -+ exit /b 1 -+) -+ -+if "%1" == "html" ( -+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished. The HTML pages are in %BUILDDIR%/html. -+ goto end -+) -+ -+if "%1" == "dirhtml" ( -+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. -+ goto end -+) -+ -+if "%1" == "singlehtml" ( -+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. -+ goto end -+) -+ -+if "%1" == "pickle" ( -+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished; now you can process the pickle files. -+ goto end -+) -+ -+if "%1" == "json" ( -+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished; now you can process the JSON files. -+ goto end -+) -+ -+if "%1" == "htmlhelp" ( -+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished; now you can run HTML Help Workshop with the ^ -+.hhp project file in %BUILDDIR%/htmlhelp. -+ goto end -+) -+ -+if "%1" == "qthelp" ( -+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished; now you can run "qcollectiongenerator" with the ^ -+.qhcp project file in %BUILDDIR%/qthelp, like this: -+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\systerspcweb.qhcp -+ echo.To view the help file: -+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\systerspcweb.ghc -+ goto end -+) -+ -+if "%1" == "devhelp" ( -+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished. -+ goto end -+) -+ -+if "%1" == "epub" ( -+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished. The epub file is in %BUILDDIR%/epub. -+ goto end -+) -+ -+if "%1" == "latex" ( -+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. -+ goto end -+) -+ -+if "%1" == "latexpdf" ( -+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex -+ cd %BUILDDIR%/latex -+ make all-pdf -+ cd %BUILDDIR%/.. -+ echo. -+ echo.Build finished; the PDF files are in %BUILDDIR%/latex. -+ goto end -+) -+ -+if "%1" == "latexpdfja" ( -+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex -+ cd %BUILDDIR%/latex -+ make all-pdf-ja -+ cd %BUILDDIR%/.. -+ echo. -+ echo.Build finished; the PDF files are in %BUILDDIR%/latex. -+ goto end -+) -+ -+if "%1" == "text" ( -+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished. The text files are in %BUILDDIR%/text. -+ goto end -+) -+ -+if "%1" == "man" ( -+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished. The manual pages are in %BUILDDIR%/man. -+ goto end -+) -+ -+if "%1" == "texinfo" ( -+ %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. -+ goto end -+) -+ -+if "%1" == "gettext" ( -+ %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished. The message catalogs are in %BUILDDIR%/locale. -+ goto end -+) -+ -+if "%1" == "changes" ( -+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.The overview file is in %BUILDDIR%/changes. -+ goto end -+) -+ -+if "%1" == "linkcheck" ( -+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Link check complete; look for any errors in the above output ^ -+or in %BUILDDIR%/linkcheck/output.txt. -+ goto end -+) -+ -+if "%1" == "doctest" ( -+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Testing of doctests in the sources finished, look at the ^ -+results in %BUILDDIR%/doctest/output.txt. -+ goto end -+) -+ -+if "%1" == "xml" ( -+ %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished. The XML files are in %BUILDDIR%/xml. -+ goto end -+) -+ -+if "%1" == "pseudoxml" ( -+ %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml -+ if errorlevel 1 exit /b 1 -+ echo. -+ echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. -+ goto end -+) -+ -+:end -diff --git a/webhub/models.py b/webhub/models.py -index bd1a959..9143ea1 100644 ---- a/webhub/models.py -+++ b/webhub/models.py -@@ -226,34 +226,34 @@ class Outcome(models.Model): - return unicode(self.outcome_value) - - --class Cohurt(models.Model): -+class Cohort(models.Model): - #name -- cohurt_name = models.CharField(max_length=300) -+ cohort_name = models.CharField(max_length=300) - #short description -- cohurt_desc = models.CharField(max_length=3000) -+ cohort_desc = models.CharField(max_length=3000) - #no of members -- cohurt_no_of_members = models.IntegerField() -+ cohort_no_of_members = models.IntegerField() - #age range -- cohurt_age = models.CharField(max_length=30) -+ cohort_age = models.CharField(max_length=30) - #no of males -- cohurt_males = models.IntegerField() -+ cohort_males = models.IntegerField() - #no of females -- cohurt_females = models.IntegerField() -+ cohort_females = models.IntegerField() - #position within the community -- cohurt_pos = models.CharField(max_length=30) -+ cohort_pos = models.CharField(max_length=30) - #other relevant notes -- cohurt_notes = models.CharField(max_length=3000) -+ cohort_notes = models.CharField(max_length=3000) - - def __unicode__(self): -- return unicode(self.cohurt_name) -+ return unicode(self.cohort_name) - - class Activity(models.Model): - #title of the activity - activity_title = models.CharField(max_length=300) - #short description - activity_desc = models.CharField(max_length=3000) -- #relevant cohurt name -- activity_cohurt = models.ForeignKey(Cohurt, null=False, related_name='activity_cohurt') -+ #relevant cohort name -+ activity_cohort = models.ForeignKey(Cohort, null=False, related_name='activity_cohort') - #date & time of the activity creation - activity_created = models.DateTimeField(auto_now_add=True) - #output with which the activity is associated -@@ -267,8 +267,8 @@ class Measurement(models.Model): - meas_title = models.CharField(max_length=300) - #short description of the Measurement - meas_desc = models.CharField(max_length=3000) -- #relevant cohurt name -- meas_cohurt = models.ForeignKey(Output, null=False, related_name='meas_cohurt') -+ #relevant cohort name -+ meas_cohort = models.ForeignKey(Output, null=False, related_name='meas_cohort') - #date & time of the Measurement creation - meas_created = models.DateTimeField(auto_now_add=True) - #outcome with which the Measurement is associated -@@ -292,8 +292,8 @@ class Volunteer(models.Model): - vol_activity = models.ManyToManyField(Activity) - #measurement - vol_meas = models.ManyToManyField(Measurement) -- #cohurt -- vol_cohurt = models.ManyToManyField(Cohurt) -+ #cohort -+ vol_cohort = models.ManyToManyField(Cohort) - - def __unicode__(self): - return self.vol_name -diff --git a/webhub/serializers.pyc b/webhub/serializers.pyc -index 3572e06..902ff82 100644 -Binary files a/webhub/serializers.pyc and b/webhub/serializers.pyc differ -diff --git a/webhub/systerspcweb.txt b/webhub/systerspcweb.txt -new file mode 100644 -index 0000000..01325ed ---- /dev/null -+++ b/webhub/systerspcweb.txt -@@ -0,0 +1,26 @@ -+.. systerspcweb documentation master file, created by -+ sphinx-quickstart on Wed Aug 13 20:07:49 2014. -+ You can adapt this file completely to your liking, but it should at least -+ contain the root `toctree` directive. -+ -+Welcome to systerspcweb's documentation! -+======================================== -+ -+Contents: -+ -+.. toctree:: -+ :maxdepth: 2 -+ -+.. automodule:: serializers.py -+ -+.. autoclass:: UserSerializer -+ :members: -+ -+ -+Indices and tables -+================== -+ -+* :ref:`genindex` -+* :ref:`modindex` -+* :ref:`search` -+ -diff --git a/webhub/systerspcweb.txt~ b/webhub/systerspcweb.txt~ -new file mode 100644 -index 0000000..01325ed ---- /dev/null -+++ b/webhub/systerspcweb.txt~ -@@ -0,0 +1,26 @@ -+.. systerspcweb documentation master file, created by -+ sphinx-quickstart on Wed Aug 13 20:07:49 2014. -+ You can adapt this file completely to your liking, but it should at least -+ contain the root `toctree` directive. -+ -+Welcome to systerspcweb's documentation! -+======================================== -+ -+Contents: -+ -+.. toctree:: -+ :maxdepth: 2 -+ -+.. automodule:: serializers.py -+ -+.. autoclass:: UserSerializer -+ :members: -+ -+ -+Indices and tables -+================== -+ -+* :ref:`genindex` -+* :ref:`modindex` -+* :ref:`search` -+ - -commit 3e5cf1ad035cb60a8927a8289fd028db384c89e3 -Author: desaivaibhavi -Date: Tue Aug 12 19:28:50 2014 +0530 - - documentation for api added - -diff --git a/docs/DocumentationusingAPIs.pdf b/docs/DocumentationusingAPIs.pdf -new file mode 100644 -index 0000000..43a7f43 -Binary files /dev/null and b/docs/DocumentationusingAPIs.pdf differ - -commit b376e315b37621493c0a43aa2ded653217e982a0 -Author: desaivaibhavi -Date: Sun Aug 10 02:29:53 2014 +0530 - - resolving smtp issue - -diff --git a/infohub/settings.py b/infohub/settings.py -index 4525c09..071648e 100644 ---- a/infohub/settings.py -+++ b/infohub/settings.py -@@ -111,8 +111,10 @@ ALLOWED_HOSTS = ['*'] - - - #settings for smtp -+EMAIL_USE_TLS = True -+DEFAULT_FROM_EMAIL = 'ranipc93@gmail.com' -+SERVER_EMAIL = 'ranipc93@gmail.com' - EMAIL_HOST = 'smtp.gmail.com' - EMAIL_HOST_USER = 'ranipc93@gmail.com' - EMAIL_HOST_PASSWORD = 'ranipc1993' - EMAIL_PORT = 465 --EMAIL_USE_TLS = True -\ No newline at end of file - -commit 25186b9654130a16fcaf9d855a6d67d5ab6ecfcf -Author: desaivaibhavi -Date: Sat Aug 9 18:28:29 2014 +0530 - - settings for smtp - -diff --git a/infohub/settings.py b/infohub/settings.py -index 71bd228..4525c09 100644 ---- a/infohub/settings.py -+++ b/infohub/settings.py -@@ -108,3 +108,11 @@ SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') - - # Allow all host headers - ALLOWED_HOSTS = ['*'] -+ -+ -+#settings for smtp -+EMAIL_HOST = 'smtp.gmail.com' -+EMAIL_HOST_USER = 'ranipc93@gmail.com' -+EMAIL_HOST_PASSWORD = 'ranipc1993' -+EMAIL_PORT = 465 -+EMAIL_USE_TLS = True -\ No newline at end of file - -commit fd2611d7d077e098a16439cd6f55053c17e38174 -Author: desaivaibhavi -Date: Sat Aug 9 18:13:38 2014 +0530 - - changing url from localhost - -diff --git a/webhub/views.py b/webhub/views.py -index d092d39..b29223a 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -35,7 +35,7 @@ import smtplib - SMTP_PORT = 465 - - #link for the localhost --website = "http://192.168.33.10:8000" -+website = "http://systerspcweb.herokuapp.com/" - - jinja_environ = jinja2.Environment(loader=jinja2.FileSystemLoader(['ui']), extensions=[loopcontrols]) - - -commit 67fcb2c9c35ae3bbf0e042707badad662d4d4d12 -Merge: e1daef0 01bb016 -Author: desaivaibhavi -Date: Sat Aug 9 12:59:11 2014 +0530 - - changes after hosting - -commit 01bb016ba4ae955d9b1257516008c64d2ef0897d -Author: desaivaibhavi -Date: Thu Aug 7 14:54:29 2014 +0000 - - latest changes - -diff --git a/ui/test.html b/ui/test.html -new file mode 100644 -index 0000000..e0d91c3 ---- /dev/null -+++ b/ui/test.html -@@ -0,0 +1,17 @@ -+ -+ -+ -+ -+ -+ -+ Test Page -+ -+ -+ No of worksheets {{no}} -+ -+ -\ No newline at end of file -diff --git a/webhub/PKG-INFO b/webhub/PKG-INFO -new file mode 100644 -index 0000000..513bf98 ---- /dev/null -+++ b/webhub/PKG-INFO -@@ -0,0 +1,21 @@ -+Metadata-Version: 1.0 -+Name: xlrd -+Version: 0.9.3 -+Summary: Library for developers to extract data from Microsoft Excel (tm) spreadsheet files -+Home-page: http://www.python-excel.org/ -+Author: John Machin -+Author-email: sjmachin@lexicon.net -+License: BSD -+Description: Extract data from Excel spreadsheets (.xls and .xlsx, versions 2.0 onwards) on any platform. Pure Python (2.6, 2.7, 3.2+). Strong support for Excel dates. Unicode-aware. -+Keywords: xls,excel,spreadsheet,workbook -+Platform: Any platform -- don't need Windows -+Classifier: Development Status :: 5 - Production/Stable -+Classifier: Intended Audience :: Developers -+Classifier: License :: OSI Approved :: BSD License -+Classifier: Programming Language :: Python -+Classifier: Programming Language :: Python :: 2 -+Classifier: Programming Language :: Python :: 3 -+Classifier: Operating System :: OS Independent -+Classifier: Topic :: Database -+Classifier: Topic :: Office/Business -+Classifier: Topic :: Software Development :: Libraries :: Python Modules -diff --git a/webhub/README.html b/webhub/README.html -new file mode 100644 -index 0000000..bbc3675 ---- /dev/null -+++ b/webhub/README.html -@@ -0,0 +1,135 @@ -+ -+ -+ -+ -+The xlrd Module -- README -+ -+ -+ -+

Python package "xlrd"

-+ -+

Purpose: Provide a library for developers to use to extract data -+ from Microsoft Excel (tm) spreadsheet files. -+ It is not an end-user tool. -+

-+

Author: John Machin, Lingfo Pty Ltd (sjmachin@lexicon.net) -+

-+

Licence: BSD-style (see licences.py) -+

-+

Version of xlrd: 0.7.1 -- 2009-05-31 -+

-+

Versions of Python supported: 2.6-2.7. -+

-+

External modules required: -+

-+
The package itself is pure Python with no dependencies on modules or packages -+ outside the standard Python distribution. -+
-+
-+

Versions of Excel supported: -+ 2004, 2003, XP, 2000, 97, 95, 5.0, 4.0, 3.0, 2.1, 2.0. -+ Support for Excel 2007 .xlsx files scheduled for version 0.7.1. -+

-+

Outside the current scope: xlrd will safely and reliably ignore any of these -+if present in the file: -+

-+
    -+
  • Charts, Macros, Pictures, any other embedded object. WARNING: currently -+ this includes embedded worksheets. -+
  • -+
  • VBA modules -+
  • -+
  • Formulas (results of formula calculations are extracted, of course). -+
  • -+
  • Comments -+
  • -+
  • Hyperlinks -+
  • -+
  • Autofilters, advanced filters, pivot tables, conditional formatting, data validation -+
  • -+
-+

Unlikely to be done: -+

-+
  • Handling password-protected (encrypted) files. -+
  • -+
-+

Particular emphasis (refer docs for details): -+

-+
  • Operability across OS, regions, platforms -+
  • -+
  • Handling Excel's date problems, including the Windows / Macintosh -+ four-year differential. -+
  • -+
  • Providing access to named constants and named groups of cells (from version 0.6.0) -+
  • -+
  • Providing access to "visual" information: font, "number format", background, border, -+ alignment and protection for cells, height/width etc for rows/columns (from version 0.6.1) -+
  • -+
-+

Quick start: -+

-+
    import xlrd
-+    book = xlrd.open_workbook("myfile.xls")
-+    print "The number of worksheets is", book.nsheets
-+    print "Worksheet name(s):", book.sheet_names()
-+    sh = book.sheet_by_index(0)
-+    print sh.name, sh.nrows, sh.ncols
-+    print "Cell D30 is", sh.cell_value(rowx=29, colx=3)
-+    for rx in range(sh.nrows):
-+        print sh.row(rx)
-+    # Refer to docs for more details.
-+    # Feedback on API is welcomed.
-+

-+

-+

Another quick start: This will show the first, second and last rows of each -+ sheet in each file: -+

-+ -+
    OS-prompt>python PYDIR/scripts/runxlrd.py 3rows *blah*.xls
-+ -+

Installation: -+

-+
  • On Windows: use the installer. -+
  • -+
  • Any OS: Unzip the .zip file into a suitable directory, -+ chdir to that directory, then do "python setup.py install". -+
  • -+
  • If PYDIR is your Python installation directory: -+ the main files are in PYDIR/Lib/site-packages/xlrd -+ the docs are in the doc subdirectory, -+ and there's a sample script: PYDIR/Scripts/runxlrd.py -+
  • -+
  • If os.sep != "/": make the appropriate adjustments. -+
  • -+
-+

Download URLs: -+

-+
  • http://pypi.python.org/pypi/xlrd -+
  • -+
  • http://www.lexicon.net/sjmachin/xlrd.htm -+
  • -+
-+

Acknowledgements: -+

-+
  • This package started life as a translation from C into Python -+of parts of a utility called "xlreader" developed by David Giffin. -+"This product includes software developed by David Giffin <david@giffin.org>." -+
  • -+
  • OpenOffice.org has truly excellent documentation of the Microsoft Excel file formats -+and Compound Document file format, authored by Daniel Rentz. See http://sc.openoffice.org -+
  • -+
  • U+5F20 U+654F: over a decade of inspiration, support, and interesting decoding opportunities. -+
  • -+
  • Ksenia Marasanova: sample Macintosh and non-Latin1 files, alpha testing -+
  • -+
  • Backporting to Python 2.1 was partially funded by Journyx - provider of -+timesheet and project accounting solutions (http://journyx.com/). -+
  • -+
  • Provision of formatting information in version 0.6.1 was funded by Simplistix Ltd -+ (http://www.simplistix.co.uk/) -+
  • -+
  • << a growing list of names; see HISTORY.html >>: feedback, testing, test files, ... -+
-+ -+ -+ -diff --git a/webhub/Updated Project Framework Indicator List PeaceTrack.xlsx b/webhub/Updated Project Framework Indicator List PeaceTrack.xlsx -new file mode 100644 -index 0000000..a227790 -Binary files /dev/null and b/webhub/Updated Project Framework Indicator List PeaceTrack.xlsx differ -diff --git a/webhub/database.py b/webhub/database.py -new file mode 100644 -index 0000000..bc3e62a ---- /dev/null -+++ b/webhub/database.py -@@ -0,0 +1,4 @@ -+#Version : Phython/Django 2.7.6, PostgreSQL 9.3.4 -+#Author : Vaibhavi Desai -+#Github username : desaivaibhavi -+#email : ranihaileydesai@gmail.com -\ No newline at end of file -diff --git a/webhub/scripts/runxlrd.py b/webhub/scripts/runxlrd.py -new file mode 100644 -index 0000000..f26067e ---- /dev/null -+++ b/webhub/scripts/runxlrd.py -@@ -0,0 +1,414 @@ -+#!/usr/bin/env python -+# Copyright (c) 2005-2012 Stephen John Machin, Lingfo Pty Ltd -+# This script is part of the xlrd package, which is released under a -+# BSD-style licence. -+ -+from __future__ import print_function -+ -+cmd_doc = """ -+Commands: -+ -+2rows Print the contents of first and last row in each sheet -+3rows Print the contents of first, second and last row in each sheet -+bench Same as "show", but doesn't print -- for profiling -+biff_count[1] Print a count of each type of BIFF record in the file -+biff_dump[1] Print a dump (char and hex) of the BIFF records in the file -+fonts hdr + print a dump of all font objects -+hdr Mini-overview of file (no per-sheet information) -+hotshot Do a hotshot profile run e.g. ... -f1 hotshot bench bigfile*.xls -+labels Dump of sheet.col_label_ranges and ...row... for each sheet -+name_dump Dump of each object in book.name_obj_list -+names Print brief information for each NAME record -+ov Overview of file -+profile Like "hotshot", but uses cProfile -+show Print the contents of all rows in each sheet -+version[0] Print versions of xlrd and Python and exit -+xfc Print "XF counts" and cell-type counts -- see code for details -+ -+[0] means no file arg -+[1] means only one file arg i.e. no glob.glob pattern -+""" -+ -+options = None -+if __name__ == "__main__": -+ -+ PSYCO = 0 -+ -+ import xlrd -+ import sys, time, glob, traceback, gc -+ -+ from xlrd.timemachine import xrange, REPR -+ -+ -+ class LogHandler(object): -+ -+ def __init__(self, logfileobj): -+ self.logfileobj = logfileobj -+ self.fileheading = None -+ self.shown = 0 -+ -+ def setfileheading(self, fileheading): -+ self.fileheading = fileheading -+ self.shown = 0 -+ -+ def write(self, text): -+ if self.fileheading and not self.shown: -+ self.logfileobj.write(self.fileheading) -+ self.shown = 1 -+ self.logfileobj.write(text) -+ -+ null_cell = xlrd.empty_cell -+ -+ def show_row(bk, sh, rowx, colrange, printit): -+ if bk.ragged_rows: -+ colrange = range(sh.row_len(rowx)) -+ if not colrange: return -+ if printit: print() -+ if bk.formatting_info: -+ for colx, ty, val, cxfx in get_row_data(bk, sh, rowx, colrange): -+ if printit: -+ print("cell %s%d: type=%d, data: %r, xfx: %s" -+ % (xlrd.colname(colx), rowx+1, ty, val, cxfx)) -+ else: -+ for colx, ty, val, _unused in get_row_data(bk, sh, rowx, colrange): -+ if printit: -+ print("cell %s%d: type=%d, data: %r" % (xlrd.colname(colx), rowx+1, ty, val)) -+ -+ def get_row_data(bk, sh, rowx, colrange): -+ result = [] -+ dmode = bk.datemode -+ ctys = sh.row_types(rowx) -+ cvals = sh.row_values(rowx) -+ for colx in colrange: -+ cty = ctys[colx] -+ cval = cvals[colx] -+ if bk.formatting_info: -+ cxfx = str(sh.cell_xf_index(rowx, colx)) -+ else: -+ cxfx = '' -+ if cty == xlrd.XL_CELL_DATE: -+ try: -+ showval = xlrd.xldate_as_tuple(cval, dmode) -+ except xlrd.XLDateError as e: -+ showval = "%s:%s" % (type(e).__name__, e) -+ cty = xlrd.XL_CELL_ERROR -+ elif cty == xlrd.XL_CELL_ERROR: -+ showval = xlrd.error_text_from_code.get(cval, '' % cval) -+ else: -+ showval = cval -+ result.append((colx, cty, showval, cxfx)) -+ return result -+ -+ def bk_header(bk): -+ print() -+ print("BIFF version: %s; datemode: %s" -+ % (xlrd.biff_text_from_num[bk.biff_version], bk.datemode)) -+ print("codepage: %r (encoding: %s); countries: %r" -+ % (bk.codepage, bk.encoding, bk.countries)) -+ print("Last saved by: %r" % bk.user_name) -+ print("Number of data sheets: %d" % bk.nsheets) -+ print("Use mmap: %d; Formatting: %d; On demand: %d" -+ % (bk.use_mmap, bk.formatting_info, bk.on_demand)) -+ print("Ragged rows: %d" % bk.ragged_rows) -+ if bk.formatting_info: -+ print("FORMATs: %d, FONTs: %d, XFs: %d" -+ % (len(bk.format_list), len(bk.font_list), len(bk.xf_list))) -+ if not options.suppress_timing: -+ print("Load time: %.2f seconds (stage 1) %.2f seconds (stage 2)" -+ % (bk.load_time_stage_1, bk.load_time_stage_2)) -+ print() -+ -+ def show_fonts(bk): -+ print("Fonts:") -+ for x in xrange(len(bk.font_list)): -+ font = bk.font_list[x] -+ font.dump(header='== Index %d ==' % x, indent=4) -+ -+ def show_names(bk, dump=0): -+ bk_header(bk) -+ if bk.biff_version < 50: -+ print("Names not extracted in this BIFF version") -+ return -+ nlist = bk.name_obj_list -+ print("Name list: %d entries" % len(nlist)) -+ for nobj in nlist: -+ if dump: -+ nobj.dump(sys.stdout, -+ header="\n=== Dump of name_obj_list[%d] ===" % nobj.name_index) -+ else: -+ print("[%d]\tName:%r macro:%r scope:%d\n\tresult:%r\n" -+ % (nobj.name_index, nobj.name, nobj.macro, nobj.scope, nobj.result)) -+ -+ def print_labels(sh, labs, title): -+ if not labs:return -+ for rlo, rhi, clo, chi in labs: -+ print("%s label range %s:%s contains:" -+ % (title, xlrd.cellname(rlo, clo), xlrd.cellname(rhi-1, chi-1))) -+ for rx in xrange(rlo, rhi): -+ for cx in xrange(clo, chi): -+ print(" %s: %r" % (xlrd.cellname(rx, cx), sh.cell_value(rx, cx))) -+ -+ def show_labels(bk): -+ # bk_header(bk) -+ hdr = 0 -+ for shx in range(bk.nsheets): -+ sh = bk.sheet_by_index(shx) -+ clabs = sh.col_label_ranges -+ rlabs = sh.row_label_ranges -+ if clabs or rlabs: -+ if not hdr: -+ bk_header(bk) -+ hdr = 1 -+ print("sheet %d: name = %r; nrows = %d; ncols = %d" % -+ (shx, sh.name, sh.nrows, sh.ncols)) -+ print_labels(sh, clabs, 'Col') -+ print_labels(sh, rlabs, 'Row') -+ if bk.on_demand: bk.unload_sheet(shx) -+ -+ def show(bk, nshow=65535, printit=1): -+ bk_header(bk) -+ if 0: -+ rclist = xlrd.sheet.rc_stats.items() -+ rclist = sorted(rclist) -+ print("rc stats") -+ for k, v in rclist: -+ print("0x%04x %7d" % (k, v)) -+ if options.onesheet: -+ try: -+ shx = int(options.onesheet) -+ except ValueError: -+ shx = bk.sheet_by_name(options.onesheet).number -+ shxrange = [shx] -+ else: -+ shxrange = range(bk.nsheets) -+ # print("shxrange", list(shxrange)) -+ for shx in shxrange: -+ sh = bk.sheet_by_index(shx) -+ nrows, ncols = sh.nrows, sh.ncols -+ colrange = range(ncols) -+ anshow = min(nshow, nrows) -+ print("sheet %d: name = %s; nrows = %d; ncols = %d" % -+ (shx, REPR(sh.name), sh.nrows, sh.ncols)) -+ if nrows and ncols: -+ # Beat the bounds -+ for rowx in xrange(nrows): -+ nc = sh.row_len(rowx) -+ if nc: -+ _junk = sh.row_types(rowx)[nc-1] -+ _junk = sh.row_values(rowx)[nc-1] -+ _junk = sh.cell(rowx, nc-1) -+ for rowx in xrange(anshow-1): -+ if not printit and rowx % 10000 == 1 and rowx > 1: -+ print("done %d rows" % (rowx-1,)) -+ show_row(bk, sh, rowx, colrange, printit) -+ if anshow and nrows: -+ show_row(bk, sh, nrows-1, colrange, printit) -+ print() -+ if bk.on_demand: bk.unload_sheet(shx) -+ -+ def count_xfs(bk): -+ bk_header(bk) -+ for shx in range(bk.nsheets): -+ sh = bk.sheet_by_index(shx) -+ nrows, ncols = sh.nrows, sh.ncols -+ print("sheet %d: name = %r; nrows = %d; ncols = %d" % -+ (shx, sh.name, sh.nrows, sh.ncols)) -+ # Access all xfindexes to force gathering stats -+ type_stats = [0, 0, 0, 0, 0, 0, 0] -+ for rowx in xrange(nrows): -+ for colx in xrange(sh.row_len(rowx)): -+ xfx = sh.cell_xf_index(rowx, colx) -+ assert xfx >= 0 -+ cty = sh.cell_type(rowx, colx) -+ type_stats[cty] += 1 -+ print("XF stats", sh._xf_index_stats) -+ print("type stats", type_stats) -+ print() -+ if bk.on_demand: bk.unload_sheet(shx) -+ -+ def main(cmd_args): -+ import optparse -+ global options, PSYCO -+ usage = "\n%prog [options] command [input-file-patterns]\n" + cmd_doc -+ oparser = optparse.OptionParser(usage) -+ oparser.add_option( -+ "-l", "--logfilename", -+ default="", -+ help="contains error messages") -+ oparser.add_option( -+ "-v", "--verbosity", -+ type="int", default=0, -+ help="level of information and diagnostics provided") -+ oparser.add_option( -+ "-m", "--mmap", -+ type="int", default=-1, -+ help="1: use mmap; 0: don't use mmap; -1: accept heuristic") -+ oparser.add_option( -+ "-e", "--encoding", -+ default="", -+ help="encoding override") -+ oparser.add_option( -+ "-f", "--formatting", -+ type="int", default=0, -+ help="0 (default): no fmt info\n" -+ "1: fmt info (all cells)\n" -+ ) -+ oparser.add_option( -+ "-g", "--gc", -+ type="int", default=0, -+ help="0: auto gc enabled; 1: auto gc disabled, manual collect after each file; 2: no gc") -+ oparser.add_option( -+ "-s", "--onesheet", -+ default="", -+ help="restrict output to this sheet (name or index)") -+ oparser.add_option( -+ "-u", "--unnumbered", -+ action="store_true", default=0, -+ help="omit line numbers or offsets in biff_dump") -+ oparser.add_option( -+ "-d", "--on-demand", -+ action="store_true", default=0, -+ help="load sheets on demand instead of all at once") -+ oparser.add_option( -+ "-t", "--suppress-timing", -+ action="store_true", default=0, -+ help="don't print timings (diffs are less messy)") -+ oparser.add_option( -+ "-r", "--ragged-rows", -+ action="store_true", default=0, -+ help="open_workbook(..., ragged_rows=True)") -+ options, args = oparser.parse_args(cmd_args) -+ if len(args) == 1 and args[0] in ("version", ): -+ pass -+ elif len(args) < 2: -+ oparser.error("Expected at least 2 args, found %d" % len(args)) -+ cmd = args[0] -+ xlrd_version = getattr(xlrd, "__VERSION__", "unknown; before 0.5") -+ if cmd == 'biff_dump': -+ xlrd.dump(args[1], unnumbered=options.unnumbered) -+ sys.exit(0) -+ if cmd == 'biff_count': -+ xlrd.count_records(args[1]) -+ sys.exit(0) -+ if cmd == 'version': -+ print("xlrd: %s, from %s" % (xlrd_version, xlrd.__file__)) -+ print("Python:", sys.version) -+ sys.exit(0) -+ if options.logfilename: -+ logfile = LogHandler(open(options.logfilename, 'w')) -+ else: -+ logfile = sys.stdout -+ mmap_opt = options.mmap -+ mmap_arg = xlrd.USE_MMAP -+ if mmap_opt in (1, 0): -+ mmap_arg = mmap_opt -+ elif mmap_opt != -1: -+ print('Unexpected value (%r) for mmap option -- assuming default' % mmap_opt) -+ fmt_opt = options.formatting | (cmd in ('xfc', )) -+ gc_mode = options.gc -+ if gc_mode: -+ gc.disable() -+ for pattern in args[1:]: -+ for fname in glob.glob(pattern): -+ print("\n=== File: %s ===" % fname) -+ if logfile != sys.stdout: -+ logfile.setfileheading("\n=== File: %s ===\n" % fname) -+ if gc_mode == 1: -+ n_unreachable = gc.collect() -+ if n_unreachable: -+ print("GC before open:", n_unreachable, "unreachable objects") -+ if PSYCO: -+ import psyco -+ psyco.full() -+ PSYCO = 0 -+ try: -+ t0 = time.time() -+ bk = xlrd.open_workbook(fname, -+ verbosity=options.verbosity, logfile=logfile, -+ use_mmap=mmap_arg, -+ encoding_override=options.encoding, -+ formatting_info=fmt_opt, -+ on_demand=options.on_demand, -+ ragged_rows=options.ragged_rows, -+ ) -+ t1 = time.time() -+ if not options.suppress_timing: -+ print("Open took %.2f seconds" % (t1-t0,)) -+ except xlrd.XLRDError as e: -+ print("*** Open failed: %s: %s" % (type(e).__name__, e)) -+ continue -+ except KeyboardInterrupt: -+ print("*** KeyboardInterrupt ***") -+ traceback.print_exc(file=sys.stdout) -+ sys.exit(1) -+ except BaseException as e: -+ print("*** Open failed: %s: %s" % (type(e).__name__, e)) -+ traceback.print_exc(file=sys.stdout) -+ continue -+ t0 = time.time() -+ if cmd == 'hdr': -+ bk_header(bk) -+ elif cmd == 'ov': # OverView -+ show(bk, 0) -+ elif cmd == 'show': # all rows -+ show(bk) -+ elif cmd == '2rows': # first row and last row -+ show(bk, 2) -+ elif cmd == '3rows': # first row, 2nd row and last row -+ show(bk, 3) -+ elif cmd == 'bench': -+ show(bk, printit=0) -+ elif cmd == 'fonts': -+ bk_header(bk) -+ show_fonts(bk) -+ elif cmd == 'names': # named reference list -+ show_names(bk) -+ elif cmd == 'name_dump': # named reference list -+ show_names(bk, dump=1) -+ elif cmd == 'labels': -+ show_labels(bk) -+ elif cmd == 'xfc': -+ count_xfs(bk) -+ else: -+ print("*** Unknown command <%s>" % cmd) -+ sys.exit(1) -+ del bk -+ if gc_mode == 1: -+ n_unreachable = gc.collect() -+ if n_unreachable: -+ print("GC post cmd:", fname, "->", n_unreachable, "unreachable objects") -+ if not options.suppress_timing: -+ t1 = time.time() -+ print("\ncommand took %.2f seconds\n" % (t1-t0,)) -+ -+ return None -+ -+ av = sys.argv[1:] -+ if not av: -+ main(av) -+ firstarg = av[0].lower() -+ if firstarg == "hotshot": -+ import hotshot, hotshot.stats -+ av = av[1:] -+ prof_log_name = "XXXX.prof" -+ prof = hotshot.Profile(prof_log_name) -+ # benchtime, result = prof.runcall(main, *av) -+ result = prof.runcall(main, *(av, )) -+ print("result", repr(result)) -+ prof.close() -+ stats = hotshot.stats.load(prof_log_name) -+ stats.strip_dirs() -+ stats.sort_stats('time', 'calls') -+ stats.print_stats(20) -+ elif firstarg == "profile": -+ import cProfile -+ av = av[1:] -+ cProfile.run('main(av)', 'YYYY.prof') -+ import pstats -+ p = pstats.Stats('YYYY.prof') -+ p.strip_dirs().sort_stats('cumulative').print_stats(30) -+ elif firstarg == "psyco": -+ PSYCO = 1 -+ main(av[1:]) -+ else: -+ main(av) -diff --git a/webhub/setup.py b/webhub/setup.py -new file mode 100644 -index 0000000..c563faf ---- /dev/null -+++ b/webhub/setup.py -@@ -0,0 +1,57 @@ -+#!/usr/bin/env python -+ -+from os import path -+import sys -+python_version = sys.version_info[:2] -+ -+if python_version < (2, 6): -+ raise Exception("This version of xlrd requires Python 2.6 or above. " -+ "For older versions of Python, you can use the 0.8 series.") -+ -+av = sys.argv -+if len(av) > 1 and av[1].lower() == "--egg": -+ del av[1] -+ from setuptools import setup -+else: -+ from distutils.core import setup -+ -+from xlrd.info import __VERSION__ -+ -+setup( -+ name = 'xlrd', -+ version = __VERSION__, -+ author = 'John Machin', -+ author_email = 'sjmachin@lexicon.net', -+ url = 'http://www.python-excel.org/', -+ packages = ['xlrd'], -+ scripts = [ -+ 'scripts/runxlrd.py', -+ ], -+ package_data={ -+ 'xlrd': [ -+ 'doc/*.htm*', -+ # 'doc/*.txt', -+ 'examples/*.*', -+ ], -+ -+ }, -+ description = 'Library for developers to extract data from Microsoft Excel (tm) spreadsheet files', -+ long_description = \ -+ "Extract data from Excel spreadsheets (.xls and .xlsx, versions 2.0 onwards) on any platform. " \ -+ "Pure Python (2.6, 2.7, 3.2+). Strong support for Excel dates. Unicode-aware.", -+ platforms = ["Any platform -- don't need Windows"], -+ license = 'BSD', -+ keywords = ['xls', 'excel', 'spreadsheet', 'workbook'], -+ classifiers = [ -+ 'Development Status :: 5 - Production/Stable', -+ 'Intended Audience :: Developers', -+ 'License :: OSI Approved :: BSD License', -+ 'Programming Language :: Python', -+ 'Programming Language :: Python :: 2', -+ 'Programming Language :: Python :: 3', -+ 'Operating System :: OS Independent', -+ 'Topic :: Database', -+ 'Topic :: Office/Business', -+ 'Topic :: Software Development :: Libraries :: Python Modules', -+ ], -+ ) -diff --git a/webhub/tests/Formate.xls b/webhub/tests/Formate.xls -new file mode 100644 -index 0000000..808cafb -Binary files /dev/null and b/webhub/tests/Formate.xls differ -diff --git a/webhub/tests/__init__.py b/webhub/tests/__init__.py -new file mode 100644 -index 0000000..e69de29 -diff --git a/webhub/tests/base.py b/webhub/tests/base.py -new file mode 100644 -index 0000000..d7a577a ---- /dev/null -+++ b/webhub/tests/base.py -@@ -0,0 +1,4 @@ -+import os -+ -+def from_this_dir(filename): -+ return os.path.join(os.path.dirname(os.path.abspath(__file__)), filename) -diff --git a/webhub/tests/formula_test_names.xls b/webhub/tests/formula_test_names.xls -new file mode 100644 -index 0000000..b6d98c7 -Binary files /dev/null and b/webhub/tests/formula_test_names.xls differ -diff --git a/webhub/tests/formula_test_sjmachin.xls b/webhub/tests/formula_test_sjmachin.xls -new file mode 100644 -index 0000000..8217008 -Binary files /dev/null and b/webhub/tests/formula_test_sjmachin.xls differ -diff --git a/webhub/tests/issue20.xls b/webhub/tests/issue20.xls -new file mode 100644 -index 0000000..d017343 -Binary files /dev/null and b/webhub/tests/issue20.xls differ -diff --git a/webhub/tests/merged_cells.xlsx b/webhub/tests/merged_cells.xlsx -new file mode 100644 -index 0000000..2d94fa2 -Binary files /dev/null and b/webhub/tests/merged_cells.xlsx differ -diff --git a/webhub/tests/picture_in_cell.xls b/webhub/tests/picture_in_cell.xls -new file mode 100644 -index 0000000..fa62e28 -Binary files /dev/null and b/webhub/tests/picture_in_cell.xls differ -diff --git a/webhub/tests/profiles.xls b/webhub/tests/profiles.xls -new file mode 100644 -index 0000000..1254f02 -Binary files /dev/null and b/webhub/tests/profiles.xls differ -diff --git a/webhub/tests/ragged.xls b/webhub/tests/ragged.xls -new file mode 100644 -index 0000000..2bef15b -Binary files /dev/null and b/webhub/tests/ragged.xls differ -diff --git a/webhub/tests/reveng1.xlsx b/webhub/tests/reveng1.xlsx -new file mode 100644 -index 0000000..099e26b -Binary files /dev/null and b/webhub/tests/reveng1.xlsx differ -diff --git a/webhub/tests/test_biffh.py b/webhub/tests/test_biffh.py -new file mode 100644 -index 0000000..3a253ad ---- /dev/null -+++ b/webhub/tests/test_biffh.py -@@ -0,0 +1,22 @@ -+import unittest -+import sys -+ -+if sys.version_info[0] >= 3: -+ from io import StringIO -+else: -+ # Python 2.6+ does have the io module, but io.StringIO is strict about -+ # unicode, which won't work for our test. -+ from StringIO import StringIO -+ -+from xlrd import biffh -+ -+class TestHexDump(unittest.TestCase): -+ def test_hex_char_dump(self): -+ sio = StringIO() -+ biffh.hex_char_dump(b"abc\0e\01", 0, 6, fout=sio) -+ s = sio.getvalue() -+ assert "61 62 63 00 65 01" in s, s -+ assert "abc~e?" in s, s -+ -+if __name__=='__main__': -+ unittest.main() -diff --git a/webhub/tests/test_cell.py b/webhub/tests/test_cell.py -new file mode 100644 -index 0000000..3190ef7 ---- /dev/null -+++ b/webhub/tests/test_cell.py -@@ -0,0 +1,64 @@ -+# Portions Copyright (C) 2010, Manfred Moitzi under a BSD licence -+ -+import sys -+import os -+import unittest -+ -+import xlrd -+ -+from .base import from_this_dir -+ -+class TestCell(unittest.TestCase): -+ -+ def setUp(self): -+ self.book = xlrd.open_workbook(from_this_dir('profiles.xls'), formatting_info=True) -+ self.sheet = self.book.sheet_by_name('PROFILEDEF') -+ -+ def test_string_cell(self): -+ cell = self.sheet.cell(0, 0) -+ self.assertEqual(cell.ctype, xlrd.book.XL_CELL_TEXT) -+ self.assertEqual(cell.value, 'PROFIL') -+ self.assertTrue(cell.xf_index > 0) -+ -+ def test_number_cell(self): -+ cell = self.sheet.cell(1, 1) -+ self.assertEqual(cell.ctype, xlrd.book.XL_CELL_NUMBER) -+ self.assertEqual(cell.value, 100) -+ self.assertTrue(cell.xf_index > 0) -+ -+ def test_calculated_cell(self): -+ sheet2 = self.book.sheet_by_name('PROFILELEVELS') -+ cell = sheet2.cell(1, 3) -+ self.assertEqual(cell.ctype, xlrd.book.XL_CELL_NUMBER) -+ self.assertAlmostEqual(cell.value, 265.131, places=3) -+ self.assertTrue(cell.xf_index > 0) -+ -+ def test_merged_cells(self): -+ book = xlrd.open_workbook(from_this_dir('xf_class.xls'), formatting_info=True) -+ sheet3 = book.sheet_by_name('table2') -+ row_lo, row_hi, col_lo, col_hi = sheet3.merged_cells[0] -+ self.assertEqual(sheet3.cell(row_lo, col_lo).value, 'MERGED') -+ self.assertEqual((row_lo, row_hi, col_lo, col_hi), (3, 7, 2, 5)) -+ -+ def test_merged_cells_xlsx(self): -+ book = xlrd.open_workbook(from_this_dir('merged_cells.xlsx')) -+ -+ sheet1 = book.sheet_by_name('Sheet1') -+ expected = [] -+ got = sheet1.merged_cells -+ self.assertEqual(expected, got) -+ -+ sheet2 = book.sheet_by_name('Sheet2') -+ expected = [(0, 1, 0, 2)] -+ got = sheet2.merged_cells -+ self.assertEqual(expected, got) -+ -+ sheet3 = book.sheet_by_name('Sheet3') -+ expected = [(0, 1, 0, 2), (0, 1, 2, 4), (1, 4, 0, 2), (1, 9, 2, 4)] -+ got = sheet3.merged_cells -+ self.assertEqual(expected, got) -+ -+ sheet4 = book.sheet_by_name('Sheet4') -+ expected = [(0, 1, 0, 2), (2, 20, 0, 1), (1, 6, 2, 5)] -+ got = sheet4.merged_cells -+ self.assertEqual(expected, got) -diff --git a/webhub/tests/test_comments_excel.xlsx b/webhub/tests/test_comments_excel.xlsx -new file mode 100644 -index 0000000..cdc2465 -Binary files /dev/null and b/webhub/tests/test_comments_excel.xlsx differ -diff --git a/webhub/tests/test_comments_gdocs.xlsx b/webhub/tests/test_comments_gdocs.xlsx -new file mode 100644 -index 0000000..2f8e5e1 -Binary files /dev/null and b/webhub/tests/test_comments_gdocs.xlsx differ -diff --git a/webhub/tests/test_formats.py b/webhub/tests/test_formats.py -new file mode 100644 -index 0000000..559ad13 ---- /dev/null -+++ b/webhub/tests/test_formats.py -@@ -0,0 +1,77 @@ -+ # -*- coding: utf-8 -*- -+ # Portions Copyright (C) 2010, Manfred Moitzi under a BSD licence -+ -+from unittest import TestCase -+import sys -+import os -+ -+import xlrd -+ -+if sys.version_info[0] >= 3: -+ def u(s): return s -+else: -+ def u(s): -+ return s.decode('utf-8') -+ -+from .base import from_this_dir -+ -+class TestCellContent(TestCase): -+ -+ def setUp(self): -+ self.book = xlrd.open_workbook(from_this_dir('Formate.xls'), formatting_info=True) -+ self.sheet = self.book.sheet_by_name(u('Blätt1')) -+ -+ def test_text_cells(self): -+ for row, name in enumerate([u('Huber'), u('Äcker'), u('Öcker')]): -+ cell = self.sheet.cell(row, 0) -+ self.assertEqual(cell.ctype, xlrd.book.XL_CELL_TEXT) -+ self.assertEqual(cell.value, name) -+ self.assertTrue(cell.xf_index > 0) -+ -+ def test_date_cells(self): -+ # see also 'Dates in Excel spreadsheets' in the documentation -+ # convert: xldate_as_tuple(float, book.datemode) -> (year, month, -+ # day, hour, minutes, seconds) -+ for row, date in [(0, 2741.), (1, 38406.), (2, 32266.)]: -+ cell = self.sheet.cell(row, 1) -+ self.assertEqual(cell.ctype, xlrd.book.XL_CELL_DATE) -+ self.assertEqual(cell.value, date) -+ self.assertTrue(cell.xf_index > 0) -+ -+ def test_time_cells(self): -+ # see also 'Dates in Excel spreadsheets' in the documentation -+ # convert: xldate_as_tuple(float, book.datemode) -> (year, month, -+ # day, hour, minutes, seconds) -+ for row, time in [(3, .273611), (4, .538889), (5, .741123)]: -+ cell = self.sheet.cell(row, 1) -+ self.assertEqual(cell.ctype, xlrd.book.XL_CELL_DATE) -+ self.assertAlmostEqual(cell.value, time, places=6) -+ self.assertTrue(cell.xf_index > 0) -+ -+ def test_percent_cells(self): -+ for row, time in [(6, .974), (7, .124)]: -+ cell = self.sheet.cell(row, 1) -+ self.assertEqual(cell.ctype, xlrd.book.XL_CELL_NUMBER) -+ self.assertAlmostEqual(cell.value, time, places=3) -+ self.assertTrue(cell.xf_index > 0) -+ -+ def test_currency_cells(self): -+ for row, time in [(8, 1000.30), (9, 1.20)]: -+ cell = self.sheet.cell(row, 1) -+ self.assertEqual(cell.ctype, xlrd.book.XL_CELL_NUMBER) -+ self.assertAlmostEqual(cell.value, time, places=2) -+ self.assertTrue(cell.xf_index > 0) -+ -+ def test_get_from_merged_cell(self): -+ sheet = self.book.sheet_by_name(u('ÖÄÜ')) -+ cell = sheet.cell(2, 2) -+ self.assertEqual(cell.ctype, xlrd.book.XL_CELL_TEXT) -+ self.assertEqual(cell.value, 'MERGED CELLS') -+ self.assertTrue(cell.xf_index > 0) -+ -+ def test_ignore_diagram(self): -+ sheet = self.book.sheet_by_name(u('Blätt3')) -+ cell = sheet.cell(0, 0) -+ self.assertEqual(cell.ctype, xlrd.book.XL_CELL_NUMBER) -+ self.assertEqual(cell.value, 100) -+ self.assertTrue(cell.xf_index > 0) -diff --git a/webhub/tests/test_formulas.py b/webhub/tests/test_formulas.py -new file mode 100644 -index 0000000..acf6d24 ---- /dev/null -+++ b/webhub/tests/test_formulas.py -@@ -0,0 +1,83 @@ -+ # -*- coding: utf-8 -*- -+# Portions Copyright (C) 2010, Manfred Moitzi under a BSD licence -+ -+from unittest import TestCase -+import os -+import sys -+ -+import xlrd -+ -+from .base import from_this_dir -+ -+try: -+ ascii -+except NameError: -+ # For Python 2 -+ def ascii(s): -+ a = repr(s) -+ if a.startswith(('u"', "u'")): -+ a = a[1:] -+ return a -+ -+class TestFormulas(TestCase): -+ -+ def setUp(self): -+ book = xlrd.open_workbook(from_this_dir('formula_test_sjmachin.xls')) -+ self.sheet = book.sheet_by_index(0) -+ -+ def get_value(self, col, row): -+ return ascii(self.sheet.col_values(col)[row]) -+ -+ def test_cell_B2(self): -+ self.assertEqual( -+ self.get_value(1, 1), -+ r"'\u041c\u041e\u0421\u041a\u0412\u0410 \u041c\u043e\u0441\u043a\u0432\u0430'" -+ ) -+ -+ def test_cell_B3(self): -+ self.assertEqual(self.get_value(1, 2), '0.14285714285714285') -+ -+ def test_cell_B4(self): -+ self.assertEqual(self.get_value(1, 3), "'ABCDEF'") -+ -+ def test_cell_B5(self): -+ self.assertEqual(self.get_value(1, 4), "''") -+ -+ def test_cell_B6(self): -+ self.assertEqual(self.get_value(1, 5), '1') -+ -+ def test_cell_B7(self): -+ self.assertEqual(self.get_value(1, 6), '7') -+ -+ def test_cell_B8(self): -+ self.assertEqual( -+ self.get_value(1, 7), -+ r"'\u041c\u041e\u0421\u041a\u0412\u0410 \u041c\u043e\u0441\u043a\u0432\u0430'" -+ ) -+ -+class TestNameFormulas(TestCase): -+ -+ def setUp(self): -+ book = xlrd.open_workbook(from_this_dir('formula_test_names.xls')) -+ self.sheet = book.sheet_by_index(0) -+ -+ def get_value(self, col, row): -+ return ascii(self.sheet.col_values(col)[row]) -+ -+ def test_unaryop(self): -+ self.assertEqual(self.get_value(1, 1), '-7.0') -+ -+ def test_attrsum(self): -+ self.assertEqual(self.get_value(1, 2), '4.0') -+ -+ def test_func(self): -+ self.assertEqual(self.get_value(1, 3), '6.0') -+ -+ def test_func_var_args(self): -+ self.assertEqual(self.get_value(1, 4), '3.0') -+ -+ def test_if(self): -+ self.assertEqual(self.get_value(1, 5), "'b'") -+ -+ def test_choose(self): -+ self.assertEqual(self.get_value(1, 6), "'C'") -diff --git a/webhub/tests/test_open_workbook.py b/webhub/tests/test_open_workbook.py -new file mode 100644 -index 0000000..70edd95 ---- /dev/null -+++ b/webhub/tests/test_open_workbook.py -@@ -0,0 +1,38 @@ -+from unittest import TestCase -+ -+import os -+ -+from xlrd import open_workbook -+ -+from .base import from_this_dir -+ -+class TestOpen(TestCase): -+ # test different uses of open_workbook -+ -+ def test_names_demo(self): -+ # For now, we just check this doesn't raise an error. -+ open_workbook( -+ from_this_dir(os.path.join('..','xlrd','examples','namesdemo.xls')) -+ ) -+ -+ def test_ragged_rows_tidied_with_formatting(self): -+ # For now, we just check this doesn't raise an error. -+ open_workbook(from_this_dir('issue20.xls'), -+ formatting_info=True) -+ -+ def test_BYTES_X00(self): -+ # For now, we just check this doesn't raise an error. -+ open_workbook(from_this_dir('picture_in_cell.xls'), -+ formatting_info=True) -+ -+ def test_xlsx_simple(self): -+ # For now, we just check this doesn't raise an error. -+ open_workbook(from_this_dir('text_bar.xlsx')) -+ # we should make assertions here that data has been -+ # correctly processed. -+ -+ def test_xlsx(self): -+ # For now, we just check this doesn't raise an error. -+ open_workbook(from_this_dir('reveng1.xlsx')) -+ # we should make assertions here that data has been -+ # correctly processed. -diff --git a/webhub/tests/test_sheet.py b/webhub/tests/test_sheet.py -new file mode 100644 -index 0000000..e1da4a9 ---- /dev/null -+++ b/webhub/tests/test_sheet.py -@@ -0,0 +1,128 @@ -+# Portions Copyright (C) 2010, Manfred Moitzi under a BSD licence -+ -+from unittest import TestCase -+ -+import sys -+import os -+import unittest -+ -+import xlrd -+ -+from .base import from_this_dir -+ -+SHEETINDEX = 0 -+NROWS = 15 -+NCOLS = 13 -+ -+ROW_ERR = NROWS + 10 -+COL_ERR = NCOLS + 10 -+ -+class TestSheet(TestCase): -+ -+ sheetnames = ['PROFILEDEF', 'AXISDEF', 'TRAVERSALCHAINAGE', -+ 'AXISDATUMLEVELS', 'PROFILELEVELS'] -+ -+ def setUp(self): -+ self.book = xlrd.open_workbook(from_this_dir('profiles.xls'), formatting_info=True) -+ -+ def check_sheet_function(self, function): -+ self.assertTrue(function(0, 0)) -+ self.assertTrue(function(NROWS-1, NCOLS-1)) -+ -+ def check_sheet_function_index_error(self, function): -+ self.assertRaises(IndexError, function, ROW_ERR, 0) -+ self.assertRaises(IndexError, function, 0, COL_ERR) -+ -+ def check_col_slice(self, col_function): -+ _slice = col_function(0, 2, NROWS-2) -+ self.assertEqual(len(_slice), NROWS-4) -+ -+ def check_row_slice(self, row_function): -+ _slice = row_function(0, 2, NCOLS-2) -+ self.assertEqual(len(_slice), NCOLS-4) -+ -+ def test_nrows(self): -+ sheet = self.book.sheet_by_index(SHEETINDEX) -+ self.assertEqual(sheet.nrows, NROWS) -+ -+ def test_ncols(self): -+ sheet = self.book.sheet_by_index(SHEETINDEX) -+ self.assertEqual(sheet.ncols, NCOLS) -+ -+ def test_cell(self): -+ sheet = self.book.sheet_by_index(SHEETINDEX) -+ self.assertNotEqual(xlrd.empty_cell, sheet.cell(0, 0)) -+ self.assertNotEqual(xlrd.empty_cell, sheet.cell(NROWS-1, NCOLS-1)) -+ -+ def test_cell_error(self): -+ sheet = self.book.sheet_by_index(SHEETINDEX) -+ self.check_sheet_function_index_error(sheet.cell) -+ -+ def test_cell_type(self): -+ sheet = self.book.sheet_by_index(SHEETINDEX) -+ self.check_sheet_function(sheet.cell_type) -+ -+ def test_cell_type_error(self): -+ sheet = self.book.sheet_by_index(SHEETINDEX) -+ self.check_sheet_function_index_error(sheet.cell_type) -+ -+ def test_cell_value(self): -+ sheet = self.book.sheet_by_index(SHEETINDEX) -+ self.check_sheet_function(sheet.cell_value) -+ -+ def test_cell_value_error(self): -+ sheet = self.book.sheet_by_index(SHEETINDEX) -+ self.check_sheet_function_index_error(sheet.cell_value) -+ -+ def test_cell_xf_index(self): -+ sheet = self.book.sheet_by_index(SHEETINDEX) -+ self.check_sheet_function(sheet.cell_xf_index) -+ -+ def test_cell_xf_index_error(self): -+ sheet = self.book.sheet_by_index(SHEETINDEX) -+ self.check_sheet_function_index_error(sheet.cell_xf_index) -+ -+ def test_col(self): -+ sheet = self.book.sheet_by_index(SHEETINDEX) -+ col = sheet.col(0) -+ self.assertEqual(len(col), NROWS) -+ -+ def test_row(self): -+ sheet = self.book.sheet_by_index(SHEETINDEX) -+ row = sheet.row(0) -+ self.assertEqual(len(row), NCOLS) -+ -+ def test_col_slice(self): -+ sheet = self.book.sheet_by_index(SHEETINDEX) -+ self.check_col_slice(sheet.col_slice) -+ -+ def test_col_types(self): -+ sheet = self.book.sheet_by_index(SHEETINDEX) -+ self.check_col_slice(sheet.col_types) -+ -+ def test_col_values(self): -+ sheet = self.book.sheet_by_index(SHEETINDEX) -+ self.check_col_slice(sheet.col_values) -+ -+ def test_row_slice(self): -+ sheet = self.book.sheet_by_index(SHEETINDEX) -+ self.check_row_slice(sheet.row_slice) -+ -+ def test_row_types(self): -+ sheet = self.book.sheet_by_index(SHEETINDEX) -+ self.check_row_slice(sheet.col_types) -+ -+ def test_row_values(self): -+ sheet = self.book.sheet_by_index(SHEETINDEX) -+ self.check_col_slice(sheet.row_values) -+ -+class TestSheetRagged(TestCase): -+ -+ def test_read_ragged(self): -+ book = xlrd.open_workbook(from_this_dir('ragged.xls'), ragged_rows=True) -+ sheet = book.sheet_by_index(0) -+ self.assertEqual(sheet.row_len(0), 3) -+ self.assertEqual(sheet.row_len(1), 2) -+ self.assertEqual(sheet.row_len(2), 1) -+ self.assertEqual(sheet.row_len(3), 4) -+ self.assertEqual(sheet.row_len(4), 4) -diff --git a/webhub/tests/test_workbook.py b/webhub/tests/test_workbook.py -new file mode 100644 -index 0000000..b9caddf ---- /dev/null -+++ b/webhub/tests/test_workbook.py -@@ -0,0 +1,47 @@ -+# Portions Copyright (C) 2010, Manfred Moitzi under a BSD licence -+ -+from unittest import TestCase -+import os -+import sys -+ -+from xlrd import open_workbook -+from xlrd.book import Book -+from xlrd.sheet import Sheet -+ -+from .base import from_this_dir -+ -+class TestWorkbook(TestCase): -+ -+ sheetnames = ['PROFILEDEF', 'AXISDEF', 'TRAVERSALCHAINAGE', -+ 'AXISDATUMLEVELS', 'PROFILELEVELS'] -+ -+ def setUp(self): -+ self.book = open_workbook(from_this_dir('profiles.xls')) -+ -+ def test_open_workbook(self): -+ self.assertTrue(isinstance(self.book, Book)) -+ -+ def test_nsheets(self): -+ self.assertEqual(self.book.nsheets, 5) -+ -+ def test_sheet_by_name(self): -+ for name in self.sheetnames: -+ sheet = self.book.sheet_by_name(name) -+ self.assertTrue(isinstance(sheet, Sheet)) -+ self.assertEqual(name, sheet.name) -+ -+ def test_sheet_by_index(self): -+ for index in range(5): -+ sheet = self.book.sheet_by_index(index) -+ self.assertTrue(isinstance(sheet, Sheet)) -+ self.assertEqual(sheet.name, self.sheetnames[index]) -+ -+ def test_sheets(self): -+ sheets = self.book.sheets() -+ for index, sheet in enumerate(sheets): -+ self.assertTrue(isinstance(sheet, Sheet)) -+ self.assertEqual(sheet.name, self.sheetnames[index]) -+ -+ def test_sheet_names(self): -+ self.assertEqual(self.sheetnames, self.book.sheet_names()) -+ -diff --git a/webhub/tests/test_xldate.py b/webhub/tests/test_xldate.py -new file mode 100644 -index 0000000..0a3a1a5 ---- /dev/null -+++ b/webhub/tests/test_xldate.py -@@ -0,0 +1,57 @@ -+#!/usr/bin/env python -+# Author: mozman -+# Purpose: test xldate.py -+# Created: 04.12.2010 -+# Copyright (C) 2010, Manfred Moitzi -+# License: BSD licence -+ -+import sys -+import unittest -+ -+from xlrd import xldate -+ -+DATEMODE = 0 # 1900-based -+ -+class TestXLDate(unittest.TestCase): -+ def test_date_as_tuple(self): -+ date = xldate.xldate_as_tuple(2741., DATEMODE) -+ self.assertEqual(date, (1907, 7, 3, 0, 0, 0)) -+ date = xldate.xldate_as_tuple(38406., DATEMODE) -+ self.assertEqual(date, (2005, 2, 23, 0, 0, 0)) -+ date = xldate.xldate_as_tuple(32266., DATEMODE) -+ self.assertEqual(date, (1988, 5, 3, 0, 0, 0)) -+ -+ def test_time_as_tuple(self): -+ time = xldate.xldate_as_tuple(.273611, DATEMODE) -+ self.assertEqual(time, (0, 0, 0, 6, 34, 0)) -+ time = xldate.xldate_as_tuple(.538889, DATEMODE) -+ self.assertEqual(time, (0, 0, 0, 12, 56, 0)) -+ time = xldate.xldate_as_tuple(.741123, DATEMODE) -+ self.assertEqual(time, (0, 0, 0, 17, 47, 13)) -+ -+ def test_xldate_from_date_tuple(self): -+ date = xldate.xldate_from_date_tuple( (1907, 7, 3), DATEMODE ) -+ self.assertAlmostEqual(date, 2741.) -+ date = xldate.xldate_from_date_tuple( (2005, 2, 23), DATEMODE ) -+ self.assertAlmostEqual(date, 38406.) -+ date = xldate.xldate_from_date_tuple( (1988, 5, 3), DATEMODE ) -+ self.assertAlmostEqual(date, 32266.) -+ -+ def test_xldate_from_time_tuple(self): -+ time = xldate.xldate_from_time_tuple( (6, 34, 0) ) -+ self.assertAlmostEqual(time, .273611, places=6) -+ time = xldate.xldate_from_time_tuple( (12, 56, 0) ) -+ self.assertAlmostEqual(time, .538889, places=6) -+ time = xldate.xldate_from_time_tuple( (17, 47, 13) ) -+ self.assertAlmostEqual(time, .741123, places=6) -+ -+ def test_xldate_from_datetime_tuple(self): -+ date = xldate.xldate_from_datetime_tuple( (1907, 7, 3, 6, 34, 0), DATEMODE) -+ self.assertAlmostEqual(date, 2741.273611, places=6) -+ date = xldate.xldate_from_datetime_tuple( (2005, 2, 23, 12, 56, 0), DATEMODE) -+ self.assertAlmostEqual(date, 38406.538889, places=6) -+ date = xldate.xldate_from_datetime_tuple( (1988, 5, 3, 17, 47, 13), DATEMODE) -+ self.assertAlmostEqual(date, 32266.741123, places=6) -+ -+if __name__=='__main__': -+ unittest.main() -diff --git a/webhub/tests/test_xldate_to_datetime.py b/webhub/tests/test_xldate_to_datetime.py -new file mode 100644 -index 0000000..302997f ---- /dev/null -+++ b/webhub/tests/test_xldate_to_datetime.py -@@ -0,0 +1,164 @@ -+############################################################################### -+# -+# Tests for the xlrd xldate.xldate_as_datetime() function. -+# -+ -+import unittest -+from datetime import datetime -+from xlrd import xldate -+ -+not_1904 = False -+is_1904 = True -+ -+ -+class TestConvertToDateTime(unittest.TestCase): -+ """ -+ Testcases to test the _xldate_to_datetime() function against dates -+ extracted from Excel files, with 1900/1904 epochs. -+ -+ """ -+ -+ def test_dates_and_times_1900_epoch(self): -+ """ -+ Test the _xldate_to_datetime() function for dates and times in -+ the Excel standard 1900 epoch. -+ -+ """ -+ # Test Excel dates strings and corresponding serial date numbers taken -+ # from an Excel file. -+ excel_dates = [ -+ # Excel's 0.0 date in the 1900 epoch is 1 day before 1900. -+ ('1899-12-31T00:00:00.000', 0), -+ -+ # Date/time before the false Excel 1900 leapday. -+ ('1900-02-28T02:11:11.986', 59.09111094906), -+ -+ # Date/time after the false Excel 1900 leapday. -+ ('1900-03-01T05:46:44.068', 61.24078782403), -+ -+ # Random date/times in Excel's 0-9999.9999+ range. -+ ('1982-08-25T00:15:20.213', 30188.010650613425), -+ ('2065-04-19T00:16:48.290', 60376.011670023145), -+ ('3222-06-11T03:08:08.251', 483014.13065105322), -+ ('4379-08-03T06:14:48.580', 905652.26028449077), -+ ('5949-12-30T12:59:54.263', 1479232.5416002662), -+ -+ # End of Excel's date range. -+ ('9999-12-31T23:59:59.000', 2958465.999988426), -+ ] -+ -+ # Convert the Excel date strings to datetime objects and compare -+ # against the dateitme return value of xldate.xldate_as_datetime(). -+ for excel_date in excel_dates: -+ exp = datetime.strptime(excel_date[0], "%Y-%m-%dT%H:%M:%S.%f") -+ got = xldate.xldate_as_datetime(excel_date[1], not_1904) -+ -+ self.assertEqual(got, exp) -+ -+ def test_dates_only_1900_epoch(self): -+ """ -+ Test the _xldate_to_datetime() function for dates in the Excel -+ standard 1900 epoch. -+ -+ """ -+ # Test Excel dates strings and corresponding serial date numbers taken -+ # from an Excel file. -+ excel_dates = [ -+ # Excel's day 0 in the 1900 epoch is 1 day before 1900. -+ ('1899-12-31', 0), -+ -+ # Excel's day 1 in the 1900 epoch. -+ ('1900-01-01', 1), -+ -+ # Date/time before the false Excel 1900 leapday. -+ ('1900-02-28', 59), -+ -+ # Date/time after the false Excel 1900 leapday. -+ ('1900-03-01', 61), -+ -+ # Random date/times in Excel's 0-9999.9999+ range. -+ ('1902-09-27', 1001), -+ ('1999-12-31', 36525), -+ ('2000-01-01', 36526), -+ ('4000-12-31', 767376), -+ ('4321-01-01', 884254), -+ ('9999-01-01', 2958101), -+ -+ # End of Excel's date range. -+ ('9999-12-31', 2958465), -+ ] -+ -+ # Convert the Excel date strings to datetime objects and compare -+ # against the dateitme return value of xldate.xldate_as_datetime(). -+ for excel_date in excel_dates: -+ exp = datetime.strptime(excel_date[0], "%Y-%m-%d") -+ got = xldate.xldate_as_datetime(excel_date[1], not_1904) -+ -+ self.assertEqual(got, exp) -+ -+ def test_dates_only_1904_epoch(self): -+ """ -+ Test the _xldate_to_datetime() function for dates in the Excel -+ Mac/1904 epoch. -+ -+ """ -+ # Test Excel dates strings and corresponding serial date numbers taken -+ # from an Excel file. -+ excel_dates = [ -+ # Excel's day 0 in the 1904 epoch. -+ ('1904-01-01', 0), -+ -+ # Random date/times in Excel's 0-9999.9999+ range. -+ ('1904-01-31', 30), -+ ('1904-08-31', 243), -+ ('1999-02-28', 34757), -+ ('1999-12-31', 35063), -+ ('2000-01-01', 35064), -+ ('2400-12-31', 181526), -+ ('4000-01-01', 765549), -+ ('9999-01-01', 2956639), -+ -+ # End of Excel's date range. -+ ('9999-12-31', 2957003), -+ ] -+ -+ # Convert the Excel date strings to datetime objects and compare -+ # against the dateitme return value of xldate.xldate_as_datetime(). -+ for excel_date in excel_dates: -+ exp = datetime.strptime(excel_date[0], "%Y-%m-%d") -+ got = xldate.xldate_as_datetime(excel_date[1], is_1904) -+ -+ self.assertEqual(got, exp) -+ -+ def test_times_only(self): -+ """ -+ Test the _xldate_to_datetime() function for times only, i.e, the -+ fractional part of the Excel date when the serial date is 0. -+ -+ """ -+ # Test Excel dates strings and corresponding serial date numbers taken -+ # from an Excel file. The 1899-12-31 date is Excel's day 0. -+ excel_dates = [ -+ # Random times in Excel's 0-0.9999+ range for 1 day. -+ ('1899-12-31T00:00:00.000', 0), -+ ('1899-12-31T00:15:20.213', 1.0650613425925924E-2), -+ ('1899-12-31T02:24:37.095', 0.10042934027777778), -+ ('1899-12-31T04:56:35.792', 0.2059698148148148), -+ ('1899-12-31T07:31:20.407', 0.31343063657407405), -+ ('1899-12-31T09:37:23.945', 0.40097158564814817), -+ ('1899-12-31T12:09:48.602', 0.50681252314814818), -+ ('1899-12-31T14:37:57.451', 0.60969271990740748), -+ ('1899-12-31T17:04:02.415', 0.71113906250000003), -+ ('1899-12-31T19:14:24.673', 0.80167445601851861), -+ ('1899-12-31T21:39:05.944', 0.90215212962962965), -+ ('1899-12-31T23:17:12.632', 0.97028509259259266), -+ ('1899-12-31T23:59:59.999', 0.99999998842592586), -+ ] -+ -+ # Convert the Excel date strings to datetime objects and compare -+ # against the dateitme return value of xldate.xldate_as_datetime(). -+ for excel_date in excel_dates: -+ exp = datetime.strptime(excel_date[0], "%Y-%m-%dT%H:%M:%S.%f") -+ got = xldate.xldate_as_datetime(excel_date[1], not_1904) -+ -+ self.assertEqual(got, exp) -diff --git a/webhub/tests/test_xlsx_comments.py b/webhub/tests/test_xlsx_comments.py -new file mode 100644 -index 0000000..456ffc1 ---- /dev/null -+++ b/webhub/tests/test_xlsx_comments.py -@@ -0,0 +1,46 @@ -+from unittest import TestCase -+ -+import os -+ -+from xlrd import open_workbook -+ -+from .base import from_this_dir -+ -+class TestXlsxComments(TestCase): -+ -+ def test_excel_comments(self): -+ book = open_workbook(from_this_dir('test_comments_excel.xlsx')) -+ sheet = book.sheet_by_index(0) -+ -+ note_map = sheet.cell_note_map -+ self.assertEqual(len(note_map), 1) -+ self.assertEqual(note_map[(0, 1)].text, 'hello') -+ -+ def test_excel_comments_multiline(self): -+ book = open_workbook(from_this_dir('test_comments_excel.xlsx')) -+ sheet = book.sheet_by_index(1) -+ -+ note_map = sheet.cell_note_map -+ self.assertEqual(note_map[(1, 2)].text, '1st line\n2nd line') -+ -+ def test_excel_comments_two_t_elements(self): -+ book = open_workbook(from_this_dir('test_comments_excel.xlsx')) -+ sheet = book.sheet_by_index(2) -+ -+ note_map = sheet.cell_note_map -+ self.assertEqual(note_map[(0, 0)].text, 'Author:\nTwo t elements') -+ -+ def test_excel_comments_no_t_elements(self): -+ book = open_workbook(from_this_dir('test_comments_excel.xlsx')) -+ sheet = book.sheet_by_index(3) -+ -+ note_map = sheet.cell_note_map -+ self.assertEqual(note_map[(0,0)].text, '') -+ -+ def test_gdocs_comments(self): -+ book = open_workbook(from_this_dir('test_comments_gdocs.xlsx')) -+ sheet = book.sheet_by_index(0) -+ -+ note_map = sheet.cell_note_map -+ self.assertEqual(len(note_map), 1) -+ self.assertEqual(note_map[(0, 1)].text, 'Just a test') -diff --git a/webhub/tests/text_bar.xlsx b/webhub/tests/text_bar.xlsx -new file mode 100644 -index 0000000..9e30e63 -Binary files /dev/null and b/webhub/tests/text_bar.xlsx differ -diff --git a/webhub/tests/xf_class.xls b/webhub/tests/xf_class.xls -new file mode 100644 -index 0000000..41db86c -Binary files /dev/null and b/webhub/tests/xf_class.xls differ -diff --git a/webhub/urls.py b/webhub/urls.py -index 7a47f57..4ded510 100644 ---- a/webhub/urls.py -+++ b/webhub/urls.py -@@ -70,6 +70,7 @@ urlpatterns = patterns('', - url(r'^helpPC/$', views.helpPC, name='helpPC'), - url(r'^volunteer/$', views.volunteer, name='volunteer'), - url(r'^summary/$', views.summary, name='summary'), -+ url(r'^testDB/$', views.testDB, name='testDB'), - ) - - -diff --git a/webhub/urls.pyc b/webhub/urls.pyc -index dab8981..fb1b381 100644 -Binary files a/webhub/urls.pyc and b/webhub/urls.pyc differ -diff --git a/webhub/views.py b/webhub/views.py -index 776e4d9..d092d39 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -27,6 +27,7 @@ from rest_framework import status - from rest_framework.decorators import api_view - from rest_framework.response import Response - from paths import cpspath -+from webhub import xlrd - - import smtplib - -@@ -1468,4 +1469,10 @@ def details(request): - def helpPC(request): - return HttpResponse(jinja_environ.get_template('helpPC.html').render({"pcuser":None})) - -+#called to test if the script is fetching data from the excel sheet -+def testDB(request): -+ book = xlrd.open_workbook("Updated Project Framework Indicator List PeaceTrack.xlsx") -+ no = book.nsheets -+ -+ return HttpResponse(jinja_environ.get_template('test.html').render({"pcuser":None, "no":no})) - -diff --git a/webhub/views.pyc b/webhub/views.pyc -index af5b4e2..c4e739d 100644 -Binary files a/webhub/views.pyc and b/webhub/views.pyc differ -diff --git a/webhub/xlrd/__init__.py b/webhub/xlrd/__init__.py -new file mode 100644 -index 0000000..423a315 ---- /dev/null -+++ b/webhub/xlrd/__init__.py -@@ -0,0 +1,461 @@ -+from os import path -+ -+from .info import __VERSION__ -+ -+#

Copyright (c) 2005-2012 Stephen John Machin, Lingfo Pty Ltd

-+#

This module is part of the xlrd package, which is released under a -+# BSD-style licence.

-+ -+from . import licences -+ -+## -+#

A Python module for extracting data from MS Excel (TM) spreadsheet files. -+#

-+# Version 0.7.4 -- April 2012 -+#

-+# -+#

General information

-+# -+#

Acknowledgements

-+# -+#

-+# Development of this module would not have been possible without the document -+# "OpenOffice.org's Documentation of the Microsoft Excel File Format" -+# ("OOo docs" for short). -+# The latest version is available from OpenOffice.org in -+# PDF format -+# and -+# ODT format. -+# Small portions of the OOo docs are reproduced in this -+# document. A study of the OOo docs is recommended for those who wish a -+# deeper understanding of the Excel file layout than the xlrd docs can provide. -+#

-+# -+#

Backporting to Python 2.1 was partially funded by -+# -+# Journyx - provider of timesheet and project accounting solutions. -+# -+#

-+# -+#

Provision of formatting information in version 0.6.1 was funded by -+# -+# Simplistix Ltd. -+# -+#

-+# -+#

Unicode

-+# -+#

This module presents all text strings as Python unicode objects. -+# From Excel 97 onwards, text in Excel spreadsheets has been stored as Unicode. -+# Older files (Excel 95 and earlier) don't keep strings in Unicode; -+# a CODEPAGE record provides a codepage number (for example, 1252) which is -+# used by xlrd to derive the encoding (for same example: "cp1252") which is -+# used to translate to Unicode.

-+# -+#

If the CODEPAGE record is missing (possible if the file was created -+# by third-party software), xlrd will assume that the encoding is ascii, and keep going. -+# If the actual encoding is not ascii, a UnicodeDecodeError exception will be raised and -+# you will need to determine the encoding yourself, and tell xlrd: -+#

-+#     book = xlrd.open_workbook(..., encoding_override="cp1252")
-+# 

-+#

If the CODEPAGE record exists but is wrong (for example, the codepage -+# number is 1251, but the strings are actually encoded in koi8_r), -+# it can be overridden using the same mechanism. -+# The supplied runxlrd.py has a corresponding command-line argument, which -+# may be used for experimentation: -+#

-+#     runxlrd.py -e koi8_r 3rows myfile.xls
-+# 

-+#

The first place to look for an encoding ("codec name") is -+# -+# the Python documentation. -+#

-+#
-+# -+#

Dates in Excel spreadsheets

-+# -+#

In reality, there are no such things. What you have are floating point -+# numbers and pious hope. -+# There are several problems with Excel dates:

-+# -+#

(1) Dates are not stored as a separate data type; they are stored as -+# floating point numbers and you have to rely on -+# (a) the "number format" applied to them in Excel and/or -+# (b) knowing which cells are supposed to have dates in them. -+# This module helps with (a) by inspecting the -+# format that has been applied to each number cell; -+# if it appears to be a date format, the cell -+# is classified as a date rather than a number. Feedback on this feature, -+# especially from non-English-speaking locales, would be appreciated.

-+# -+#

(2) Excel for Windows stores dates by default as the number of -+# days (or fraction thereof) since 1899-12-31T00:00:00. Excel for -+# Macintosh uses a default start date of 1904-01-01T00:00:00. The date -+# system can be changed in Excel on a per-workbook basis (for example: -+# Tools -> Options -> Calculation, tick the "1904 date system" box). -+# This is of course a bad idea if there are already dates in the -+# workbook. There is no good reason to change it even if there are no -+# dates in the workbook. Which date system is in use is recorded in the -+# workbook. A workbook transported from Windows to Macintosh (or vice -+# versa) will work correctly with the host Excel. When using this -+# module's xldate_as_tuple function to convert numbers from a workbook, -+# you must use the datemode attribute of the Book object. If you guess, -+# or make a judgement depending on where you believe the workbook was -+# created, you run the risk of being 1462 days out of kilter.

-+# -+#

Reference: -+# http://support.microsoft.com/default.aspx?scid=KB;EN-US;q180162

-+# -+# -+#

(3) The Excel implementation of the Windows-default 1900-based date system works on the -+# incorrect premise that 1900 was a leap year. It interprets the number 60 as meaning 1900-02-29, -+# which is not a valid date. Consequently any number less than 61 is ambiguous. Example: is 59 the -+# result of 1900-02-28 entered directly, or is it 1900-03-01 minus 2 days? The OpenOffice.org Calc -+# program "corrects" the Microsoft problem; entering 1900-02-27 causes the number 59 to be stored. -+# Save as an XLS file, then open the file with Excel -- you'll see 1900-02-28 displayed.

-+# -+#

Reference: http://support.microsoft.com/default.aspx?scid=kb;en-us;214326

-+# -+#

(4) The Macintosh-default 1904-based date system counts 1904-01-02 as day 1 and 1904-01-01 as day zero. -+# Thus any number such that (0.0 <= number < 1.0) is ambiguous. Is 0.625 a time of day (15:00:00), -+# independent of the calendar, -+# or should it be interpreted as an instant on a particular day (1904-01-01T15:00:00)? -+# The xldate_* functions in this module -+# take the view that such a number is a calendar-independent time of day (like Python's datetime.time type) for both -+# date systems. This is consistent with more recent Microsoft documentation -+# (for example, the help file for Excel 2002 which says that the first day -+# in the 1904 date system is 1904-01-02). -+# -+#

(5) Usage of the Excel DATE() function may leave strange dates in a spreadsheet. Quoting the help file, -+# in respect of the 1900 date system: "If year is between 0 (zero) and 1899 (inclusive), -+# Excel adds that value to 1900 to calculate the year. For example, DATE(108,1,2) returns January 2, 2008 (1900+108)." -+# This gimmick, semi-defensible only for arguments up to 99 and only in the pre-Y2K-awareness era, -+# means that DATE(1899, 12, 31) is interpreted as 3799-12-31.

-+# -+#

For further information, please refer to the documentation for the xldate_* functions.

-+# -+#

Named references, constants, formulas, and macros

-+# -+#

-+# A name is used to refer to a cell, a group of cells, a constant -+# value, a formula, or a macro. Usually the scope of a name is global -+# across the whole workbook. However it can be local to a worksheet. -+# For example, if the sales figures are in different cells in -+# different sheets, the user may define the name "Sales" in each -+# sheet. There are built-in names, like "Print_Area" and -+# "Print_Titles"; these two are naturally local to a sheet. -+#

-+# To inspect the names with a user interface like MS Excel, OOo Calc, -+# or Gnumeric, click on Insert/Names/Define. This will show the global -+# names, plus those local to the currently selected sheet. -+#

-+# A Book object provides two dictionaries (name_map and -+# name_and_scope_map) and a list (name_obj_list) which allow various -+# ways of accessing the Name objects. There is one Name object for -+# each NAME record found in the workbook. Name objects have many -+# attributes, several of which are relevant only when obj.macro is 1. -+#

-+# In the examples directory you will find namesdemo.xls which -+# showcases the many different ways that names can be used, and -+# xlrdnamesAPIdemo.py which offers 3 different queries for inspecting -+# the names in your files, and shows how to extract whatever a name is -+# referring to. There is currently one "convenience method", -+# Name.cell(), which extracts the value in the case where the name -+# refers to a single cell. More convenience methods are planned. The -+# source code for Name.cell (in __init__.py) is an extra source of -+# information on how the Name attributes hang together. -+#

-+# -+#

Name information is not extracted from files older than -+# Excel 5.0 (Book.biff_version < 50)

-+# -+#

Formatting

-+# -+#

Introduction

-+# -+#

This collection of features, new in xlrd version 0.6.1, is intended -+# to provide the information needed to (1) display/render spreadsheet contents -+# (say) on a screen or in a PDF file, and (2) copy spreadsheet data to another -+# file without losing the ability to display/render it.

-+# -+#

The Palette; Colour Indexes

-+# -+#

A colour is represented in Excel as a (red, green, blue) ("RGB") tuple -+# with each component in range(256). However it is not possible to access an -+# unlimited number of colours; each spreadsheet is limited to a palette of 64 different -+# colours (24 in Excel 3.0 and 4.0, 8 in Excel 2.0). Colours are referenced by an index -+# ("colour index") into this palette. -+# -+# Colour indexes 0 to 7 represent 8 fixed built-in colours: black, white, red, green, blue, -+# yellow, magenta, and cyan.

-+# -+# The remaining colours in the palette (8 to 63 in Excel 5.0 and later) -+# can be changed by the user. In the Excel 2003 UI, Tools/Options/Color presents a palette -+# of 7 rows of 8 colours. The last two rows are reserved for use in charts.
-+# The correspondence between this grid and the assigned -+# colour indexes is NOT left-to-right top-to-bottom.
-+# Indexes 8 to 15 correspond to changeable -+# parallels of the 8 fixed colours -- for example, index 7 is forever cyan; -+# index 15 starts off being cyan but can be changed by the user.
-+# -+# The default colour for each index depends on the file version; tables of the defaults -+# are available in the source code. If the user changes one or more colours, -+# a PALETTE record appears in the XLS file -- it gives the RGB values for *all* changeable -+# indexes.
-+# Note that colours can be used in "number formats": "[CYAN]...." and "[COLOR8]...." refer -+# to colour index 7; "[COLOR16]...." will produce cyan -+# unless the user changes colour index 15 to something else.
-+# -+#

In addition, there are several "magic" colour indexes used by Excel:
-+# 0x18 (BIFF3-BIFF4), 0x40 (BIFF5-BIFF8): System window text colour for border lines -+# (used in XF, CF, and WINDOW2 records)
-+# 0x19 (BIFF3-BIFF4), 0x41 (BIFF5-BIFF8): System window background colour for pattern background -+# (used in XF and CF records )
-+# 0x43: System face colour (dialogue background colour)
-+# 0x4D: System window text colour for chart border lines
-+# 0x4E: System window background colour for chart areas
-+# 0x4F: Automatic colour for chart border lines (seems to be always Black)
-+# 0x50: System ToolTip background colour (used in note objects)
-+# 0x51: System ToolTip text colour (used in note objects)
-+# 0x7FFF: System window text colour for fonts (used in FONT and CF records)
-+# Note 0x7FFF appears to be the *default* colour index. It appears quite often in FONT -+# records.
-+# -+#

Default Formatting

-+# -+# Default formatting is applied to all empty cells (those not described by a cell record). -+# Firstly row default information (ROW record, Rowinfo class) is used if available. -+# Failing that, column default information (COLINFO record, Colinfo class) is used if available. -+# As a last resort the worksheet/workbook default cell format will be used; this -+# should always be present in an Excel file, -+# described by the XF record with the fixed index 15 (0-based). By default, it uses the -+# worksheet/workbook default cell style, described by the very first XF record (index 0). -+# -+#

Formatting features not included in xlrd version 0.6.1

-+#
    -+#
  • Rich text i.e. strings containing partial bold italic -+# and underlined text, change of font inside a string, etc. -+# See OOo docs s3.4 and s3.2. -+# Rich text is included in version 0.7.2
  • -+#
  • Asian phonetic text (known as "ruby"), used for Japanese furigana. See OOo docs -+# s3.4.2 (p15)
  • -+#
  • Conditional formatting. See OOo docs -+# s5.12, s6.21 (CONDFMT record), s6.16 (CF record)
  • -+#
  • Miscellaneous sheet-level and book-level items e.g. printing layout, screen panes.
  • -+#
  • Modern Excel file versions don't keep most of the built-in -+# "number formats" in the file; Excel loads formats according to the -+# user's locale. Currently xlrd's emulation of this is limited to -+# a hard-wired table that applies to the US English locale. This may mean -+# that currency symbols, date order, thousands separator, decimals separator, etc -+# are inappropriate. Note that this does not affect users who are copying XLS -+# files, only those who are visually rendering cells.
  • -+#
-+# -+#

Loading worksheets on demand

-+# -+#

This feature, new in version 0.7.1, is governed by the on_demand argument -+# to the open_workbook() function and allows saving memory and time by loading -+# only those sheets that the caller is interested in, and releasing sheets -+# when no longer required.

-+# -+#

on_demand=False (default): No change. open_workbook() loads global data -+# and all sheets, releases resources no longer required (principally the -+# str or mmap object containing the Workbook stream), and returns.

-+# -+#

on_demand=True and BIFF version < 5.0: A warning message is emitted, -+# on_demand is recorded as False, and the old process is followed.

-+# -+#

on_demand=True and BIFF version >= 5.0: open_workbook() loads global -+# data and returns without releasing resources. At this stage, the only -+# information available about sheets is Book.nsheets and Book.sheet_names().

-+# -+#

Book.sheet_by_name() and Book.sheet_by_index() will load the requested -+# sheet if it is not already loaded.

-+# -+#

Book.sheets() will load all/any unloaded sheets.

-+# -+#

The caller may save memory by calling -+# Book.unload_sheet(sheet_name_or_index) when finished with the sheet. -+# This applies irrespective of the state of on_demand.

-+# -+#

The caller may re-load an unloaded sheet by calling Book.sheet_by_xxxx() -+# -- except if those required resources have been released (which will -+# have happened automatically when on_demand is false). This is the only -+# case where an exception will be raised.

-+# -+#

The caller may query the state of a sheet: -+# Book.sheet_loaded(sheet_name_or_index) -> a bool

-+# -+#

Book.release_resources() may used to save memory and close -+# any memory-mapped file before proceding to examine already-loaded -+# sheets. Once resources are released, no further sheets can be loaded.

-+# -+#

When using on-demand, it is advisable to ensure that -+# Book.release_resources() is always called even if an exception -+# is raised in your own code; otherwise if the input file has been -+# memory-mapped, the mmap.mmap object will not be closed and you will -+# not be able to access the physical file until your Python process -+# terminates. This can be done by calling Book.release_resources() -+# explicitly in the finally suite of a try/finally block. -+# New in xlrd 0.7.2: the Book object is a "context manager", so if -+# using Python 2.5 or later, you can wrap your code in a "with" -+# statement.

-+## -+ -+import sys, zipfile, pprint -+from . import timemachine -+from .biffh import ( -+ XLRDError, -+ biff_text_from_num, -+ error_text_from_code, -+ XL_CELL_BLANK, -+ XL_CELL_TEXT, -+ XL_CELL_BOOLEAN, -+ XL_CELL_ERROR, -+ XL_CELL_EMPTY, -+ XL_CELL_DATE, -+ XL_CELL_NUMBER -+ ) -+from .formula import * # is constrained by __all__ -+from .book import Book, colname #### TODO #### formula also has `colname` (restricted to 256 cols) -+from .sheet import empty_cell -+from .xldate import XLDateError, xldate_as_tuple -+ -+if sys.version.startswith("IronPython"): -+ # print >> sys.stderr, "...importing encodings" -+ import encodings -+ -+try: -+ import mmap -+ MMAP_AVAILABLE = 1 -+except ImportError: -+ MMAP_AVAILABLE = 0 -+USE_MMAP = MMAP_AVAILABLE -+ -+## -+# -+# Open a spreadsheet file for data extraction. -+# -+# @param filename The path to the spreadsheet file to be opened. -+# -+# @param logfile An open file to which messages and diagnostics are written. -+# -+# @param verbosity Increases the volume of trace material written to the logfile. -+# -+# @param use_mmap Whether to use the mmap module is determined heuristically. -+# Use this arg to override the result. Current heuristic: mmap is used if it exists. -+# -+# @param file_contents ... as a string or an mmap.mmap object or some other behave-alike object. -+# If file_contents is supplied, filename will not be used, except (possibly) in messages. -+# -+# @param encoding_override Used to overcome missing or bad codepage information -+# in older-version files. Refer to discussion in the Unicode section above. -+#
-- New in version 0.6.0 -+# -+# @param formatting_info Governs provision of a reference to an XF (eXtended Format) object -+# for each cell in the worksheet. -+#
Default is False. This is backwards compatible and saves memory. -+# "Blank" cells (those with their own formatting information but no data) are treated as empty -+# (by ignoring the file's BLANK and MULBLANK records). -+# It cuts off any bottom "margin" of rows of empty (and blank) cells and -+# any right "margin" of columns of empty (and blank) cells. -+# Only cell_value and cell_type are available. -+#
True provides all cells, including empty and blank cells. -+# XF information is available for each cell. -+#
-- New in version 0.6.1 -+# -+# @param on_demand Governs whether sheets are all loaded initially or when demanded -+# by the caller. Please refer back to the section "Loading worksheets on demand" for details. -+#
-- New in version 0.7.1 -+# -+# @param ragged_rows False (the default) means all rows are padded out with empty cells so that all -+# rows have the same size (Sheet.ncols). True means that there are no empty cells at the ends of rows. -+# This can result in substantial memory savings if rows are of widely varying sizes. See also the -+# Sheet.row_len() method. -+#
-- New in version 0.7.2 -+# -+# @return An instance of the Book class. -+ -+def open_workbook(filename=None, -+ logfile=sys.stdout, -+ verbosity=0, -+ use_mmap=USE_MMAP, -+ file_contents=None, -+ encoding_override=None, -+ formatting_info=False, -+ on_demand=False, -+ ragged_rows=False, -+ ): -+ peeksz = 4 -+ if file_contents: -+ peek = file_contents[:peeksz] -+ else: -+ f = open(filename, "rb") -+ peek = f.read(peeksz) -+ f.close() -+ if peek == b"PK\x03\x04": # a ZIP file -+ if file_contents: -+ zf = zipfile.ZipFile(timemachine.BYTES_IO(file_contents)) -+ else: -+ zf = zipfile.ZipFile(filename) -+ component_names = zf.namelist() -+ if verbosity: -+ logfile.write('ZIP component_names:\n') -+ pprint.pprint(component_names, logfile) -+ if 'xl/workbook.xml' in component_names: -+ from . import xlsx -+ bk = xlsx.open_workbook_2007_xml( -+ zf, -+ component_names, -+ logfile=logfile, -+ verbosity=verbosity, -+ use_mmap=use_mmap, -+ formatting_info=formatting_info, -+ on_demand=on_demand, -+ ragged_rows=ragged_rows, -+ ) -+ return bk -+ if 'xl/workbook.bin' in component_names: -+ raise XLRDError('Excel 2007 xlsb file; not supported') -+ if 'content.xml' in component_names: -+ raise XLRDError('Openoffice.org ODS file; not supported') -+ raise XLRDError('ZIP file contents not a known type of workbook') -+ -+ from . import book -+ bk = book.open_workbook_xls( -+ filename=filename, -+ logfile=logfile, -+ verbosity=verbosity, -+ use_mmap=use_mmap, -+ file_contents=file_contents, -+ encoding_override=encoding_override, -+ formatting_info=formatting_info, -+ on_demand=on_demand, -+ ragged_rows=ragged_rows, -+ ) -+ return bk -+ -+## -+# For debugging: dump an XLS file's BIFF records in char & hex. -+# @param filename The path to the file to be dumped. -+# @param outfile An open file, to which the dump is written. -+# @param unnumbered If true, omit offsets (for meaningful diffs). -+ -+def dump(filename, outfile=sys.stdout, unnumbered=False): -+ from .biffh import biff_dump -+ bk = Book() -+ bk.biff2_8_load(filename=filename, logfile=outfile, ) -+ biff_dump(bk.mem, bk.base, bk.stream_len, 0, outfile, unnumbered) -+ -+## -+# For debugging and analysis: summarise the file's BIFF records. -+# I.e. produce a sorted file of (record_name, count). -+# @param filename The path to the file to be summarised. -+# @param outfile An open file, to which the summary is written. -+ -+def count_records(filename, outfile=sys.stdout): -+ from .biffh import biff_count_records -+ bk = Book() -+ bk.biff2_8_load(filename=filename, logfile=outfile, ) -+ biff_count_records(bk.mem, bk.base, bk.stream_len, outfile) -diff --git a/webhub/xlrd/__init__.pyc b/webhub/xlrd/__init__.pyc -new file mode 100644 -index 0000000..64dea7f -Binary files /dev/null and b/webhub/xlrd/__init__.pyc differ -diff --git a/webhub/xlrd/biffh.py b/webhub/xlrd/biffh.py -new file mode 100644 -index 0000000..f3a6d4d ---- /dev/null -+++ b/webhub/xlrd/biffh.py -@@ -0,0 +1,663 @@ -+# -*- coding: cp1252 -*- -+ -+## -+# Support module for the xlrd package. -+# -+#

Portions copyright 2005-2010 Stephen John Machin, Lingfo Pty Ltd

-+#

This module is part of the xlrd package, which is released under a BSD-style licence.

-+## -+ -+# 2010-03-01 SJM Reading SCL record -+# 2010-03-01 SJM Added more record IDs for biff_dump & biff_count -+# 2008-02-10 SJM BIFF2 BLANK record -+# 2008-02-08 SJM Preparation for Excel 2.0 support -+# 2008-02-02 SJM Added suffixes (_B2, _B2_ONLY, etc) on record names for biff_dump & biff_count -+# 2007-12-04 SJM Added support for Excel 2.x (BIFF2) files. -+# 2007-09-08 SJM Avoid crash when zero-length Unicode string missing options byte. -+# 2007-04-22 SJM Remove experimental "trimming" facility. -+ -+from __future__ import print_function -+ -+DEBUG = 0 -+ -+from struct import unpack -+import sys -+from .timemachine import * -+ -+class XLRDError(Exception): -+ pass -+ -+## -+# Parent of almost all other classes in the package. Defines a common "dump" method -+# for debugging. -+ -+class BaseObject(object): -+ -+ _repr_these = [] -+ -+ ## -+ # @param f open file object, to which the dump is written -+ # @param header text to write before the dump -+ # @param footer text to write after the dump -+ # @param indent number of leading spaces (for recursive calls) -+ -+ def dump(self, f=None, header=None, footer=None, indent=0): -+ if f is None: -+ f = sys.stderr -+ if hasattr(self, "__slots__"): -+ alist = [] -+ for attr in self.__slots__: -+ alist.append((attr, getattr(self, attr))) -+ else: -+ alist = self.__dict__.items() -+ alist = sorted(alist) -+ pad = " " * indent -+ if header is not None: print(header, file=f) -+ list_type = type([]) -+ dict_type = type({}) -+ for attr, value in alist: -+ if getattr(value, 'dump', None) and attr != 'book': -+ value.dump(f, -+ header="%s%s (%s object):" % (pad, attr, value.__class__.__name__), -+ indent=indent+4) -+ elif attr not in self._repr_these and ( -+ isinstance(value, list_type) or isinstance(value, dict_type) -+ ): -+ print("%s%s: %s, len = %d" % (pad, attr, type(value), len(value)), file=f) -+ else: -+ fprintf(f, "%s%s: %r\n", pad, attr, value) -+ if footer is not None: print(footer, file=f) -+ -+FUN, FDT, FNU, FGE, FTX = range(5) # unknown, date, number, general, text -+DATEFORMAT = FDT -+NUMBERFORMAT = FNU -+ -+( -+ XL_CELL_EMPTY, -+ XL_CELL_TEXT, -+ XL_CELL_NUMBER, -+ XL_CELL_DATE, -+ XL_CELL_BOOLEAN, -+ XL_CELL_ERROR, -+ XL_CELL_BLANK, # for use in debugging, gathering stats, etc -+) = range(7) -+ -+biff_text_from_num = { -+ 0: "(not BIFF)", -+ 20: "2.0", -+ 21: "2.1", -+ 30: "3", -+ 40: "4S", -+ 45: "4W", -+ 50: "5", -+ 70: "7", -+ 80: "8", -+ 85: "8X", -+ } -+ -+## -+#

This dictionary can be used to produce a text version of the internal codes -+# that Excel uses for error cells. Here are its contents: -+#

-+# 0x00: '#NULL!',  # Intersection of two cell ranges is empty
-+# 0x07: '#DIV/0!', # Division by zero
-+# 0x0F: '#VALUE!', # Wrong type of operand
-+# 0x17: '#REF!',   # Illegal or deleted cell reference
-+# 0x1D: '#NAME?',  # Wrong function or range name
-+# 0x24: '#NUM!',   # Value range overflow
-+# 0x2A: '#N/A',    # Argument or function not available
-+# 

-+ -+error_text_from_code = { -+ 0x00: '#NULL!', # Intersection of two cell ranges is empty -+ 0x07: '#DIV/0!', # Division by zero -+ 0x0F: '#VALUE!', # Wrong type of operand -+ 0x17: '#REF!', # Illegal or deleted cell reference -+ 0x1D: '#NAME?', # Wrong function or range name -+ 0x24: '#NUM!', # Value range overflow -+ 0x2A: '#N/A', # Argument or function not available -+} -+ -+BIFF_FIRST_UNICODE = 80 -+ -+XL_WORKBOOK_GLOBALS = WBKBLOBAL = 0x5 -+XL_WORKBOOK_GLOBALS_4W = 0x100 -+XL_WORKSHEET = WRKSHEET = 0x10 -+ -+XL_BOUNDSHEET_WORKSHEET = 0x00 -+XL_BOUNDSHEET_CHART = 0x02 -+XL_BOUNDSHEET_VB_MODULE = 0x06 -+ -+# XL_RK2 = 0x7e -+XL_ARRAY = 0x0221 -+XL_ARRAY2 = 0x0021 -+XL_BLANK = 0x0201 -+XL_BLANK_B2 = 0x01 -+XL_BOF = 0x809 -+XL_BOOLERR = 0x205 -+XL_BOOLERR_B2 = 0x5 -+XL_BOUNDSHEET = 0x85 -+XL_BUILTINFMTCOUNT = 0x56 -+XL_CF = 0x01B1 -+XL_CODEPAGE = 0x42 -+XL_COLINFO = 0x7D -+XL_COLUMNDEFAULT = 0x20 # BIFF2 only -+XL_COLWIDTH = 0x24 # BIFF2 only -+XL_CONDFMT = 0x01B0 -+XL_CONTINUE = 0x3c -+XL_COUNTRY = 0x8C -+XL_DATEMODE = 0x22 -+XL_DEFAULTROWHEIGHT = 0x0225 -+XL_DEFCOLWIDTH = 0x55 -+XL_DIMENSION = 0x200 -+XL_DIMENSION2 = 0x0 -+XL_EFONT = 0x45 -+XL_EOF = 0x0a -+XL_EXTERNNAME = 0x23 -+XL_EXTERNSHEET = 0x17 -+XL_EXTSST = 0xff -+XL_FEAT11 = 0x872 -+XL_FILEPASS = 0x2f -+XL_FONT = 0x31 -+XL_FONT_B3B4 = 0x231 -+XL_FORMAT = 0x41e -+XL_FORMAT2 = 0x1E # BIFF2, BIFF3 -+XL_FORMULA = 0x6 -+XL_FORMULA3 = 0x206 -+XL_FORMULA4 = 0x406 -+XL_GCW = 0xab -+XL_HLINK = 0x01B8 -+XL_QUICKTIP = 0x0800 -+XL_HORIZONTALPAGEBREAKS = 0x1b -+XL_INDEX = 0x20b -+XL_INTEGER = 0x2 # BIFF2 only -+XL_IXFE = 0x44 # BIFF2 only -+XL_LABEL = 0x204 -+XL_LABEL_B2 = 0x04 -+XL_LABELRANGES = 0x15f -+XL_LABELSST = 0xfd -+XL_LEFTMARGIN = 0x26 -+XL_TOPMARGIN = 0x28 -+XL_RIGHTMARGIN = 0x27 -+XL_BOTTOMMARGIN = 0x29 -+XL_HEADER = 0x14 -+XL_FOOTER = 0x15 -+XL_HCENTER = 0x83 -+XL_VCENTER = 0x84 -+XL_MERGEDCELLS = 0xE5 -+XL_MSO_DRAWING = 0x00EC -+XL_MSO_DRAWING_GROUP = 0x00EB -+XL_MSO_DRAWING_SELECTION = 0x00ED -+XL_MULRK = 0xbd -+XL_MULBLANK = 0xbe -+XL_NAME = 0x18 -+XL_NOTE = 0x1c -+XL_NUMBER = 0x203 -+XL_NUMBER_B2 = 0x3 -+XL_OBJ = 0x5D -+XL_PAGESETUP = 0xA1 -+XL_PALETTE = 0x92 -+XL_PANE = 0x41 -+XL_PRINTGRIDLINES = 0x2B -+XL_PRINTHEADERS = 0x2A -+XL_RK = 0x27e -+XL_ROW = 0x208 -+XL_ROW_B2 = 0x08 -+XL_RSTRING = 0xd6 -+XL_SCL = 0x00A0 -+XL_SHEETHDR = 0x8F # BIFF4W only -+XL_SHEETPR = 0x81 -+XL_SHEETSOFFSET = 0x8E # BIFF4W only -+XL_SHRFMLA = 0x04bc -+XL_SST = 0xfc -+XL_STANDARDWIDTH = 0x99 -+XL_STRING = 0x207 -+XL_STRING_B2 = 0x7 -+XL_STYLE = 0x293 -+XL_SUPBOOK = 0x1AE # aka EXTERNALBOOK in OOo docs -+XL_TABLEOP = 0x236 -+XL_TABLEOP2 = 0x37 -+XL_TABLEOP_B2 = 0x36 -+XL_TXO = 0x1b6 -+XL_UNCALCED = 0x5e -+XL_UNKNOWN = 0xffff -+XL_VERTICALPAGEBREAKS = 0x1a -+XL_WINDOW2 = 0x023E -+XL_WINDOW2_B2 = 0x003E -+XL_WRITEACCESS = 0x5C -+XL_WSBOOL = XL_SHEETPR -+XL_XF = 0xe0 -+XL_XF2 = 0x0043 # BIFF2 version of XF record -+XL_XF3 = 0x0243 # BIFF3 version of XF record -+XL_XF4 = 0x0443 # BIFF4 version of XF record -+ -+boflen = {0x0809: 8, 0x0409: 6, 0x0209: 6, 0x0009: 4} -+bofcodes = (0x0809, 0x0409, 0x0209, 0x0009) -+ -+XL_FORMULA_OPCODES = (0x0006, 0x0406, 0x0206) -+ -+_cell_opcode_list = [ -+ XL_BOOLERR, -+ XL_FORMULA, -+ XL_FORMULA3, -+ XL_FORMULA4, -+ XL_LABEL, -+ XL_LABELSST, -+ XL_MULRK, -+ XL_NUMBER, -+ XL_RK, -+ XL_RSTRING, -+ ] -+_cell_opcode_dict = {} -+for _cell_opcode in _cell_opcode_list: -+ _cell_opcode_dict[_cell_opcode] = 1 -+ -+def is_cell_opcode(c): -+ return c in _cell_opcode_dict -+ -+def upkbits(tgt_obj, src, manifest, local_setattr=setattr): -+ for n, mask, attr in manifest: -+ local_setattr(tgt_obj, attr, (src & mask) >> n) -+ -+def upkbitsL(tgt_obj, src, manifest, local_setattr=setattr, local_int=int): -+ for n, mask, attr in manifest: -+ local_setattr(tgt_obj, attr, local_int((src & mask) >> n)) -+ -+def unpack_string(data, pos, encoding, lenlen=1): -+ nchars = unpack('<' + 'BH'[lenlen-1], data[pos:pos+lenlen])[0] -+ pos += lenlen -+ return unicode(data[pos:pos+nchars], encoding) -+ -+def unpack_string_update_pos(data, pos, encoding, lenlen=1, known_len=None): -+ if known_len is not None: -+ # On a NAME record, the length byte is detached from the front of the string. -+ nchars = known_len -+ else: -+ nchars = unpack('<' + 'BH'[lenlen-1], data[pos:pos+lenlen])[0] -+ pos += lenlen -+ newpos = pos + nchars -+ return (unicode(data[pos:newpos], encoding), newpos) -+ -+def unpack_unicode(data, pos, lenlen=2): -+ "Return unicode_strg" -+ nchars = unpack('<' + 'BH'[lenlen-1], data[pos:pos+lenlen])[0] -+ if not nchars: -+ # Ambiguous whether 0-length string should have an "options" byte. -+ # Avoid crash if missing. -+ return UNICODE_LITERAL("") -+ pos += lenlen -+ options = BYTES_ORD(data[pos]) -+ pos += 1 -+ # phonetic = options & 0x04 -+ # richtext = options & 0x08 -+ if options & 0x08: -+ # rt = unpack(' endpos=%d pos=%d endsub=%d substrg=%r\n', -+ ofs, dlen, base, endpos, pos, endsub, substrg) -+ break -+ hexd = ''.join(["%02x " % BYTES_ORD(c) for c in substrg]) -+ -+ chard = '' -+ for c in substrg: -+ c = chr(BYTES_ORD(c)) -+ if c == '\0': -+ c = '~' -+ elif not (' ' <= c <= '~'): -+ c = '?' -+ chard += c -+ if numbered: -+ num_prefix = "%5d: " % (base+pos-ofs) -+ -+ fprintf(fout, "%s %-48s %s\n", num_prefix, hexd, chard) -+ pos = endsub -+ -+def biff_dump(mem, stream_offset, stream_len, base=0, fout=sys.stdout, unnumbered=False): -+ pos = stream_offset -+ stream_end = stream_offset + stream_len -+ adj = base - stream_offset -+ dummies = 0 -+ numbered = not unnumbered -+ num_prefix = '' -+ while stream_end - pos >= 4: -+ rc, length = unpack('') -+ if numbered: -+ num_prefix = "%5d: " % (adj + pos) -+ fprintf(fout, "%s%04x %s len = %04x (%d)\n", num_prefix, rc, recname, length, length) -+ pos += 4 -+ hex_char_dump(mem, pos, length, adj+pos, fout, unnumbered) -+ pos += length -+ if dummies: -+ if numbered: -+ num_prefix = "%5d: " % (adj + savpos) -+ fprintf(fout, "%s---- %d zero bytes skipped ----\n", num_prefix, dummies) -+ if pos < stream_end: -+ if numbered: -+ num_prefix = "%5d: " % (adj + pos) -+ fprintf(fout, "%s---- Misc bytes at end ----\n", num_prefix) -+ hex_char_dump(mem, pos, stream_end-pos, adj + pos, fout, unnumbered) -+ elif pos > stream_end: -+ fprintf(fout, "Last dumped record has length (%d) that is too large\n", length) -+ -+def biff_count_records(mem, stream_offset, stream_len, fout=sys.stdout): -+ pos = stream_offset -+ stream_end = stream_offset + stream_len -+ tally = {} -+ while stream_end - pos >= 4: -+ rc, length = unpack('> sys.stderr, "...importing encodings" -+ import encodings -+ -+empty_cell = sheet.empty_cell # for exposure to the world ... -+ -+DEBUG = 0 -+ -+USE_FANCY_CD = 1 -+ -+TOGGLE_GC = 0 -+import gc -+# gc.set_debug(gc.DEBUG_STATS) -+ -+try: -+ import mmap -+ MMAP_AVAILABLE = 1 -+except ImportError: -+ MMAP_AVAILABLE = 0 -+USE_MMAP = MMAP_AVAILABLE -+ -+MY_EOF = 0xF00BAAA # not a 16-bit number -+ -+SUPBOOK_UNK, SUPBOOK_INTERNAL, SUPBOOK_EXTERNAL, SUPBOOK_ADDIN, SUPBOOK_DDEOLE = range(5) -+ -+SUPPORTED_VERSIONS = (80, 70, 50, 45, 40, 30, 21, 20) -+ -+_code_from_builtin_name = { -+ "Consolidate_Area": "\x00", -+ "Auto_Open": "\x01", -+ "Auto_Close": "\x02", -+ "Extract": "\x03", -+ "Database": "\x04", -+ "Criteria": "\x05", -+ "Print_Area": "\x06", -+ "Print_Titles": "\x07", -+ "Recorder": "\x08", -+ "Data_Form": "\x09", -+ "Auto_Activate": "\x0A", -+ "Auto_Deactivate": "\x0B", -+ "Sheet_Title": "\x0C", -+ "_FilterDatabase": "\x0D", -+ } -+builtin_name_from_code = {} -+code_from_builtin_name = {} -+for _bin, _bic in _code_from_builtin_name.items(): -+ _bin = UNICODE_LITERAL(_bin) -+ _bic = UNICODE_LITERAL(_bic) -+ code_from_builtin_name[_bin] = _bic -+ builtin_name_from_code[_bic] = _bin -+del _bin, _bic, _code_from_builtin_name -+ -+def open_workbook_xls(filename=None, -+ logfile=sys.stdout, verbosity=0, use_mmap=USE_MMAP, -+ file_contents=None, -+ encoding_override=None, -+ formatting_info=False, on_demand=False, ragged_rows=False, -+ ): -+ t0 = time.clock() -+ if TOGGLE_GC: -+ orig_gc_enabled = gc.isenabled() -+ if orig_gc_enabled: -+ gc.disable() -+ bk = Book() -+ try: -+ bk.biff2_8_load( -+ filename=filename, file_contents=file_contents, -+ logfile=logfile, verbosity=verbosity, use_mmap=use_mmap, -+ encoding_override=encoding_override, -+ formatting_info=formatting_info, -+ on_demand=on_demand, -+ ragged_rows=ragged_rows, -+ ) -+ t1 = time.clock() -+ bk.load_time_stage_1 = t1 - t0 -+ biff_version = bk.getbof(XL_WORKBOOK_GLOBALS) -+ if not biff_version: -+ raise XLRDError("Can't determine file's BIFF version") -+ if biff_version not in SUPPORTED_VERSIONS: -+ raise XLRDError( -+ "BIFF version %s is not supported" -+ % biff_text_from_num[biff_version] -+ ) -+ bk.biff_version = biff_version -+ if biff_version <= 40: -+ # no workbook globals, only 1 worksheet -+ if on_demand: -+ fprintf(bk.logfile, -+ "*** WARNING: on_demand is not supported for this Excel version.\n" -+ "*** Setting on_demand to False.\n") -+ bk.on_demand = on_demand = False -+ bk.fake_globals_get_sheet() -+ elif biff_version == 45: -+ # worksheet(s) embedded in global stream -+ bk.parse_globals() -+ if on_demand: -+ fprintf(bk.logfile, "*** WARNING: on_demand is not supported for this Excel version.\n" -+ "*** Setting on_demand to False.\n") -+ bk.on_demand = on_demand = False -+ else: -+ bk.parse_globals() -+ bk._sheet_list = [None for sh in bk._sheet_names] -+ if not on_demand: -+ bk.get_sheets() -+ bk.nsheets = len(bk._sheet_list) -+ if biff_version == 45 and bk.nsheets > 1: -+ fprintf(bk.logfile, -+ "*** WARNING: Excel 4.0 workbook (.XLW) file contains %d worksheets.\n" -+ "*** Book-level data will be that of the last worksheet.\n", -+ bk.nsheets -+ ) -+ if TOGGLE_GC: -+ if orig_gc_enabled: -+ gc.enable() -+ t2 = time.clock() -+ bk.load_time_stage_2 = t2 - t1 -+ except: -+ bk.release_resources() -+ raise -+ # normal exit -+ if not on_demand: -+ bk.release_resources() -+ return bk -+ -+## -+# For debugging: dump the file's BIFF records in char & hex. -+# @param filename The path to the file to be dumped. -+# @param outfile An open file, to which the dump is written. -+# @param unnumbered If true, omit offsets (for meaningful diffs). -+ -+def dump(filename, outfile=sys.stdout, unnumbered=False): -+ bk = Book() -+ bk.biff2_8_load(filename=filename, logfile=outfile, ) -+ biff_dump(bk.mem, bk.base, bk.stream_len, 0, outfile, unnumbered) -+ -+## -+# For debugging and analysis: summarise the file's BIFF records. -+# I.e. produce a sorted file of (record_name, count). -+# @param filename The path to the file to be summarised. -+# @param outfile An open file, to which the summary is written. -+ -+def count_records(filename, outfile=sys.stdout): -+ bk = Book() -+ bk.biff2_8_load(filename=filename, logfile=outfile, ) -+ biff_count_records(bk.mem, bk.base, bk.stream_len, outfile) -+ -+## -+# Information relating to a named reference, formula, macro, etc. -+#
-- New in version 0.6.0 -+#
-- Name information is not extracted from files older than -+# Excel 5.0 (Book.biff_version < 50) -+ -+class Name(BaseObject): -+ -+ _repr_these = ['stack'] -+ book = None # parent -+ -+ ## -+ # 0 = Visible; 1 = Hidden -+ hidden = 0 -+ -+ ## -+ # 0 = Command macro; 1 = Function macro. Relevant only if macro == 1 -+ func = 0 -+ -+ ## -+ # 0 = Sheet macro; 1 = VisualBasic macro. Relevant only if macro == 1 -+ vbasic = 0 -+ -+ ## -+ # 0 = Standard name; 1 = Macro name -+ macro = 0 -+ -+ ## -+ # 0 = Simple formula; 1 = Complex formula (array formula or user defined)
-+ # No examples have been sighted. -+ complex = 0 -+ -+ ## -+ # 0 = User-defined name; 1 = Built-in name -+ # (common examples: Print_Area, Print_Titles; see OOo docs for full list) -+ builtin = 0 -+ -+ ## -+ # Function group. Relevant only if macro == 1; see OOo docs for values. -+ funcgroup = 0 -+ -+ ## -+ # 0 = Formula definition; 1 = Binary data
No examples have been sighted. -+ binary = 0 -+ -+ ## -+ # The index of this object in book.name_obj_list -+ name_index = 0 -+ -+ ## -+ # A Unicode string. If builtin, decoded as per OOo docs. -+ name = UNICODE_LITERAL("") -+ -+ ## -+ # An 8-bit string. -+ raw_formula = b'' -+ -+ ## -+ # -1: The name is global (visible in all calculation sheets).
-+ # -2: The name belongs to a macro sheet or VBA sheet.
-+ # -3: The name is invalid.
-+ # 0 <= scope < book.nsheets: The name is local to the sheet whose index is scope. -+ scope = -1 -+ -+ ## -+ # The result of evaluating the formula, if any. -+ # If no formula, or evaluation of the formula encountered problems, -+ # the result is None. Otherwise the result is a single instance of the -+ # Operand class. -+ # -+ result = None -+ -+ ## -+ # This is a convenience method for the frequent use case where the name -+ # refers to a single cell. -+ # @return An instance of the Cell class. -+ # @throws XLRDError The name is not a constant absolute reference -+ # to a single cell. -+ def cell(self): -+ res = self.result -+ if res: -+ # result should be an instance of the Operand class -+ kind = res.kind -+ value = res.value -+ if kind == oREF and len(value) == 1: -+ ref3d = value[0] -+ if (0 <= ref3d.shtxlo == ref3d.shtxhi - 1 -+ and ref3d.rowxlo == ref3d.rowxhi - 1 -+ and ref3d.colxlo == ref3d.colxhi - 1): -+ sh = self.book.sheet_by_index(ref3d.shtxlo) -+ return sh.cell(ref3d.rowxlo, ref3d.colxlo) -+ self.dump(self.book.logfile, -+ header="=== Dump of Name object ===", -+ footer="======= End of dump =======", -+ ) -+ raise XLRDError("Not a constant absolute reference to a single cell") -+ -+ ## -+ # This is a convenience method for the use case where the name -+ # refers to one rectangular area in one worksheet. -+ # @param clipped If true (the default), the returned rectangle is clipped -+ # to fit in (0, sheet.nrows, 0, sheet.ncols) -- it is guaranteed that -+ # 0 <= rowxlo <= rowxhi <= sheet.nrows and that the number of usable rows -+ # in the area (which may be zero) is rowxhi - rowxlo; likewise for columns. -+ # @return a tuple (sheet_object, rowxlo, rowxhi, colxlo, colxhi). -+ # @throws XLRDError The name is not a constant absolute reference -+ # to a single area in a single sheet. -+ def area2d(self, clipped=True): -+ res = self.result -+ if res: -+ # result should be an instance of the Operand class -+ kind = res.kind -+ value = res.value -+ if kind == oREF and len(value) == 1: # only 1 reference -+ ref3d = value[0] -+ if 0 <= ref3d.shtxlo == ref3d.shtxhi - 1: # only 1 usable sheet -+ sh = self.book.sheet_by_index(ref3d.shtxlo) -+ if not clipped: -+ return sh, ref3d.rowxlo, ref3d.rowxhi, ref3d.colxlo, ref3d.colxhi -+ rowxlo = min(ref3d.rowxlo, sh.nrows) -+ rowxhi = max(rowxlo, min(ref3d.rowxhi, sh.nrows)) -+ colxlo = min(ref3d.colxlo, sh.ncols) -+ colxhi = max(colxlo, min(ref3d.colxhi, sh.ncols)) -+ assert 0 <= rowxlo <= rowxhi <= sh.nrows -+ assert 0 <= colxlo <= colxhi <= sh.ncols -+ return sh, rowxlo, rowxhi, colxlo, colxhi -+ self.dump(self.book.logfile, -+ header="=== Dump of Name object ===", -+ footer="======= End of dump =======", -+ ) -+ raise XLRDError("Not a constant absolute reference to a single area in a single sheet") -+ -+## -+# Contents of a "workbook". -+#

WARNING: You don't call this class yourself. You use the Book object that -+# was returned when you called xlrd.open_workbook("myfile.xls").

-+ -+class Book(BaseObject): -+ -+ ## -+ # The number of worksheets present in the workbook file. -+ # This information is available even when no sheets have yet been loaded. -+ nsheets = 0 -+ -+ ## -+ # Which date system was in force when this file was last saved.
-+ # 0 => 1900 system (the Excel for Windows default).
-+ # 1 => 1904 system (the Excel for Macintosh default).
-+ datemode = 0 # In case it's not specified in the file. -+ -+ ## -+ # Version of BIFF (Binary Interchange File Format) used to create the file. -+ # Latest is 8.0 (represented here as 80), introduced with Excel 97. -+ # Earliest supported by this module: 2.0 (represented as 20). -+ biff_version = 0 -+ -+ ## -+ # List containing a Name object for each NAME record in the workbook. -+ #
-- New in version 0.6.0 -+ name_obj_list = [] -+ -+ ## -+ # An integer denoting the character set used for strings in this file. -+ # For BIFF 8 and later, this will be 1200, meaning Unicode; more precisely, UTF_16_LE. -+ # For earlier versions, this is used to derive the appropriate Python encoding -+ # to be used to convert to Unicode. -+ # Examples: 1252 -> 'cp1252', 10000 -> 'mac_roman' -+ codepage = None -+ -+ ## -+ # The encoding that was derived from the codepage. -+ encoding = None -+ -+ ## -+ # A tuple containing the (telephone system) country code for:
-+ # [0]: the user-interface setting when the file was created.
-+ # [1]: the regional settings.
-+ # Example: (1, 61) meaning (USA, Australia). -+ # This information may give a clue to the correct encoding for an unknown codepage. -+ # For a long list of observed values, refer to the OpenOffice.org documentation for -+ # the COUNTRY record. -+ countries = (0, 0) -+ -+ ## -+ # What (if anything) is recorded as the name of the last user to save the file. -+ user_name = UNICODE_LITERAL('') -+ -+ ## -+ # A list of Font class instances, each corresponding to a FONT record. -+ #
-- New in version 0.6.1 -+ font_list = [] -+ -+ ## -+ # A list of XF class instances, each corresponding to an XF record. -+ #
-- New in version 0.6.1 -+ xf_list = [] -+ -+ ## -+ # A list of Format objects, each corresponding to a FORMAT record, in -+ # the order that they appear in the input file. -+ # It does not contain builtin formats. -+ # If you are creating an output file using (for example) pyExcelerator, -+ # use this list. -+ # The collection to be used for all visual rendering purposes is format_map. -+ #
-- New in version 0.6.1 -+ format_list = [] -+ -+ ## -+ # The mapping from XF.format_key to Format object. -+ #
-- New in version 0.6.1 -+ format_map = {} -+ -+ ## -+ # This provides access via name to the extended format information for -+ # both built-in styles and user-defined styles.
-+ # It maps name to (built_in, xf_index), where:
-+ # name is either the name of a user-defined style, -+ # or the name of one of the built-in styles. Known built-in names are -+ # Normal, RowLevel_1 to RowLevel_7, -+ # ColLevel_1 to ColLevel_7, Comma, Currency, Percent, "Comma [0]", -+ # "Currency [0]", Hyperlink, and "Followed Hyperlink".
-+ # built_in 1 = built-in style, 0 = user-defined
-+ # xf_index is an index into Book.xf_list.
-+ # References: OOo docs s6.99 (STYLE record); Excel UI Format/Style -+ #
-- New in version 0.6.1; since 0.7.4, extracted only if -+ # open_workbook(..., formatting_info=True) -+ style_name_map = {} -+ -+ ## -+ # This provides definitions for colour indexes. Please refer to the -+ # above section "The Palette; Colour Indexes" for an explanation -+ # of how colours are represented in Excel.
-+ # Colour indexes into the palette map into (red, green, blue) tuples. -+ # "Magic" indexes e.g. 0x7FFF map to None. -+ # colour_map is what you need if you want to render cells on screen or in a PDF -+ # file. If you are writing an output XLS file, use palette_record. -+ #
-- New in version 0.6.1. Extracted only if open_workbook(..., formatting_info=True) -+ colour_map = {} -+ -+ ## -+ # If the user has changed any of the colours in the standard palette, the XLS -+ # file will contain a PALETTE record with 56 (16 for Excel 4.0 and earlier) -+ # RGB values in it, and this list will be e.g. [(r0, b0, g0), ..., (r55, b55, g55)]. -+ # Otherwise this list will be empty. This is what you need if you are -+ # writing an output XLS file. If you want to render cells on screen or in a PDF -+ # file, use colour_map. -+ #
-- New in version 0.6.1. Extracted only if open_workbook(..., formatting_info=True) -+ palette_record = [] -+ -+ ## -+ # Time in seconds to extract the XLS image as a contiguous string (or mmap equivalent). -+ load_time_stage_1 = -1.0 -+ -+ ## -+ # Time in seconds to parse the data from the contiguous string (or mmap equivalent). -+ load_time_stage_2 = -1.0 -+ -+ ## -+ # @return A list of all sheets in the book. -+ # All sheets not already loaded will be loaded. -+ def sheets(self): -+ for sheetx in xrange(self.nsheets): -+ if not self._sheet_list[sheetx]: -+ self.get_sheet(sheetx) -+ return self._sheet_list[:] -+ -+ ## -+ # @param sheetx Sheet index in range(nsheets) -+ # @return An object of the Sheet class -+ def sheet_by_index(self, sheetx): -+ return self._sheet_list[sheetx] or self.get_sheet(sheetx) -+ -+ ## -+ # @param sheet_name Name of sheet required -+ # @return An object of the Sheet class -+ def sheet_by_name(self, sheet_name): -+ try: -+ sheetx = self._sheet_names.index(sheet_name) -+ except ValueError: -+ raise XLRDError('No sheet named <%r>' % sheet_name) -+ return self.sheet_by_index(sheetx) -+ -+ ## -+ # @return A list of the names of all the worksheets in the workbook file. -+ # This information is available even when no sheets have yet been loaded. -+ def sheet_names(self): -+ return self._sheet_names[:] -+ -+ ## -+ # @param sheet_name_or_index Name or index of sheet enquired upon -+ # @return true if sheet is loaded, false otherwise -+ #
-- New in version 0.7.1 -+ def sheet_loaded(self, sheet_name_or_index): -+ if isinstance(sheet_name_or_index, int): -+ sheetx = sheet_name_or_index -+ else: -+ try: -+ sheetx = self._sheet_names.index(sheet_name_or_index) -+ except ValueError: -+ raise XLRDError('No sheet named <%r>' % sheet_name_or_index) -+ return bool(self._sheet_list[sheetx]) -+ -+ ## -+ # @param sheet_name_or_index Name or index of sheet to be unloaded. -+ #
-- New in version 0.7.1 -+ def unload_sheet(self, sheet_name_or_index): -+ if isinstance(sheet_name_or_index, int): -+ sheetx = sheet_name_or_index -+ else: -+ try: -+ sheetx = self._sheet_names.index(sheet_name_or_index) -+ except ValueError: -+ raise XLRDError('No sheet named <%r>' % sheet_name_or_index) -+ self._sheet_list[sheetx] = None -+ -+ ## -+ # This method has a dual purpose. You can call it to release -+ # memory-consuming objects and (possibly) a memory-mapped file -+ # (mmap.mmap object) when you have finished loading sheets in -+ # on_demand mode, but still require the Book object to examine the -+ # loaded sheets. It is also called automatically (a) when open_workbook -+ # raises an exception and (b) if you are using a "with" statement, when -+ # the "with" block is exited. Calling this method multiple times on the -+ # same object has no ill effect. -+ def release_resources(self): -+ self._resources_released = 1 -+ if hasattr(self.mem, "close"): -+ # must be a mmap.mmap object -+ self.mem.close() -+ self.mem = None -+ if hasattr(self.filestr, "close"): -+ self.filestr.close() -+ self.filestr = None -+ self._sharedstrings = None -+ self._rich_text_runlist_map = None -+ -+ def __enter__(self): -+ return self -+ -+ def __exit__(self, exc_type, exc_value, exc_tb): -+ self.release_resources() -+ # return false -+ -+ ## -+ # A mapping from (lower_case_name, scope) to a single Name object. -+ #
-- New in version 0.6.0 -+ name_and_scope_map = {} -+ -+ ## -+ # A mapping from lower_case_name to a list of Name objects. The list is -+ # sorted in scope order. Typically there will be one item (of global scope) -+ # in the list. -+ #
-- New in version 0.6.0 -+ name_map = {} -+ -+ def __init__(self): -+ self._sheet_list = [] -+ self._sheet_names = [] -+ self._sheet_visibility = [] # from BOUNDSHEET record -+ self.nsheets = 0 -+ self._sh_abs_posn = [] # sheet's absolute position in the stream -+ self._sharedstrings = [] -+ self._rich_text_runlist_map = {} -+ self.raw_user_name = False -+ self._sheethdr_count = 0 # BIFF 4W only -+ self.builtinfmtcount = -1 # unknown as yet. BIFF 3, 4S, 4W -+ self.initialise_format_info() -+ self._all_sheets_count = 0 # includes macro & VBA sheets -+ self._supbook_count = 0 -+ self._supbook_locals_inx = None -+ self._supbook_addins_inx = None -+ self._all_sheets_map = [] # maps an all_sheets index to a calc-sheets index (or -1) -+ self._externsheet_info = [] -+ self._externsheet_type_b57 = [] -+ self._extnsht_name_from_num = {} -+ self._sheet_num_from_name = {} -+ self._extnsht_count = 0 -+ self._supbook_types = [] -+ self._resources_released = 0 -+ self.addin_func_names = [] -+ self.name_obj_list = [] -+ self.colour_map = {} -+ self.palette_record = [] -+ self.xf_list = [] -+ self.style_name_map = {} -+ self.mem = b'' -+ self.filestr = b'' -+ -+ def biff2_8_load(self, filename=None, file_contents=None, -+ logfile=sys.stdout, verbosity=0, use_mmap=USE_MMAP, -+ encoding_override=None, -+ formatting_info=False, -+ on_demand=False, -+ ragged_rows=False, -+ ): -+ # DEBUG = 0 -+ self.logfile = logfile -+ self.verbosity = verbosity -+ self.use_mmap = use_mmap and MMAP_AVAILABLE -+ self.encoding_override = encoding_override -+ self.formatting_info = formatting_info -+ self.on_demand = on_demand -+ self.ragged_rows = ragged_rows -+ -+ if not file_contents: -+ with open(filename, "rb") as f: -+ f.seek(0, 2) # EOF -+ size = f.tell() -+ f.seek(0, 0) # BOF -+ if size == 0: -+ raise XLRDError("File size is 0 bytes") -+ if self.use_mmap: -+ self.filestr = mmap.mmap(f.fileno(), size, access=mmap.ACCESS_READ) -+ self.stream_len = size -+ else: -+ self.filestr = f.read() -+ self.stream_len = len(self.filestr) -+ else: -+ self.filestr = file_contents -+ self.stream_len = len(file_contents) -+ -+ self.base = 0 -+ if self.filestr[:8] != compdoc.SIGNATURE: -+ # got this one at the antique store -+ self.mem = self.filestr -+ else: -+ cd = compdoc.CompDoc(self.filestr, logfile=self.logfile) -+ if USE_FANCY_CD: -+ for qname in ['Workbook', 'Book']: -+ self.mem, self.base, self.stream_len = \ -+ cd.locate_named_stream(UNICODE_LITERAL(qname)) -+ if self.mem: break -+ else: -+ raise XLRDError("Can't find workbook in OLE2 compound document") -+ else: -+ for qname in ['Workbook', 'Book']: -+ self.mem = cd.get_named_stream(UNICODE_LITERAL(qname)) -+ if self.mem: break -+ else: -+ raise XLRDError("Can't find workbook in OLE2 compound document") -+ self.stream_len = len(self.mem) -+ del cd -+ if self.mem is not self.filestr: -+ if hasattr(self.filestr, "close"): -+ self.filestr.close() -+ self.filestr = b'' -+ self._position = self.base -+ if DEBUG: -+ print("mem: %s, base: %d, len: %d" % (type(self.mem), self.base, self.stream_len), file=self.logfile) -+ -+ def initialise_format_info(self): -+ # needs to be done once per sheet for BIFF 4W :-( -+ self.format_map = {} -+ self.format_list = [] -+ self.xfcount = 0 -+ self.actualfmtcount = 0 # number of FORMAT records seen so far -+ self._xf_index_to_xl_type_map = {0: XL_CELL_NUMBER} -+ self._xf_epilogue_done = 0 -+ self.xf_list = [] -+ self.font_list = [] -+ -+ def get2bytes(self): -+ pos = self._position -+ buff_two = self.mem[pos:pos+2] -+ lenbuff = len(buff_two) -+ self._position += lenbuff -+ if lenbuff < 2: -+ return MY_EOF -+ lo, hi = buff_two -+ return (BYTES_ORD(hi) << 8) | BYTES_ORD(lo) -+ -+ def get_record_parts(self): -+ pos = self._position -+ mem = self.mem -+ code, length = unpack('= 2: -+ fprintf(self.logfile, -+ "BOUNDSHEET: inx=%d vis=%r sheet_name=%r abs_posn=%d sheet_type=0x%02x\n", -+ self._all_sheets_count, visibility, sheet_name, abs_posn, sheet_type) -+ self._all_sheets_count += 1 -+ if sheet_type != XL_BOUNDSHEET_WORKSHEET: -+ self._all_sheets_map.append(-1) -+ descr = { -+ 1: 'Macro sheet', -+ 2: 'Chart', -+ 6: 'Visual Basic module', -+ }.get(sheet_type, 'UNKNOWN') -+ -+ if DEBUG or self.verbosity >= 1: -+ fprintf(self.logfile, -+ "NOTE *** Ignoring non-worksheet data named %r (type 0x%02x = %s)\n", -+ sheet_name, sheet_type, descr) -+ else: -+ snum = len(self._sheet_names) -+ self._all_sheets_map.append(snum) -+ self._sheet_names.append(sheet_name) -+ self._sh_abs_posn.append(abs_posn) -+ self._sheet_visibility.append(visibility) -+ self._sheet_num_from_name[sheet_name] = snum -+ -+ def handle_builtinfmtcount(self, data): -+ ### N.B. This count appears to be utterly useless. -+ # DEBUG = 1 -+ builtinfmtcount = unpack('= 2: -+ fprintf(self.logfile, "*** No CODEPAGE record; assuming 1200 (utf_16_le)\n") -+ else: -+ codepage = self.codepage -+ if codepage in encoding_from_codepage: -+ encoding = encoding_from_codepage[codepage] -+ elif 300 <= codepage <= 1999: -+ encoding = 'cp' + str(codepage) -+ else: -+ encoding = 'unknown_codepage_' + str(codepage) -+ if DEBUG or (self.verbosity and encoding != self.encoding) : -+ fprintf(self.logfile, "CODEPAGE: codepage %r -> encoding %r\n", codepage, encoding) -+ self.encoding = encoding -+ if self.codepage != 1200: # utf_16_le -+ # If we don't have a codec that can decode ASCII into Unicode, -+ # we're well & truly stuffed -- let the punter know ASAP. -+ try: -+ _unused = unicode(b'trial', self.encoding) -+ except BaseException as e: -+ fprintf(self.logfile, -+ "ERROR *** codepage %r -> encoding %r -> %s: %s\n", -+ self.codepage, self.encoding, type(e).__name__.split(".")[-1], e) -+ raise -+ if self.raw_user_name: -+ strg = unpack_string(self.user_name, 0, self.encoding, lenlen=1) -+ strg = strg.rstrip() -+ # if DEBUG: -+ # print "CODEPAGE: user name decoded from %r to %r" % (self.user_name, strg) -+ self.user_name = strg -+ self.raw_user_name = False -+ return self.encoding -+ -+ def handle_codepage(self, data): -+ # DEBUG = 0 -+ codepage = unpack('= 2 -+ if self.biff_version >= 80: -+ option_flags, other_info =unpack("= 1 -+ blah2 = DEBUG or self.verbosity >= 2 -+ if self.biff_version >= 80: -+ num_refs = unpack("= 2: -+ logf = self.logfile -+ fprintf(logf, "FILEPASS:\n") -+ hex_char_dump(data, 0, len(data), base=0, fout=logf) -+ if self.biff_version >= 80: -+ kind1, = unpack('= 2 -+ bv = self.biff_version -+ if bv < 50: -+ return -+ self.derive_encoding() -+ # print -+ # hex_char_dump(data, 0, len(data), fout=self.logfile) -+ ( -+ option_flags, kb_shortcut, name_len, fmla_len, extsht_index, sheet_index, -+ menu_text_len, description_text_len, help_topic_text_len, status_bar_text_len, -+ ) = unpack("> nshift) -+ -+ macro_flag = " M"[nobj.macro] -+ if bv < 80: -+ internal_name, pos = unpack_string_update_pos(data, 14, self.encoding, known_len=name_len) -+ else: -+ internal_name, pos = unpack_unicode_update_pos(data, 14, known_len=name_len) -+ nobj.extn_sheet_num = extsht_index -+ nobj.excel_sheet_index = sheet_index -+ nobj.scope = None # patched up in the names_epilogue() method -+ if blah: -+ fprintf( -+ self.logfile, -+ "NAME[%d]:%s oflags=%d, name_len=%d, fmla_len=%d, extsht_index=%d, sheet_index=%d, name=%r\n", -+ name_index, macro_flag, option_flags, name_len, -+ fmla_len, extsht_index, sheet_index, internal_name) -+ name = internal_name -+ if nobj.builtin: -+ name = builtin_name_from_code.get(name, "??Unknown??") -+ if blah: print(" builtin: %s" % name, file=self.logfile) -+ nobj.name = name -+ nobj.raw_formula = data[pos:] -+ nobj.basic_formula_len = fmla_len -+ nobj.evaluated = 0 -+ if blah: -+ nobj.dump( -+ self.logfile, -+ header="--- handle_name: name[%d] ---" % name_index, -+ footer="-------------------", -+ ) -+ -+ def names_epilogue(self): -+ blah = self.verbosity >= 2 -+ f = self.logfile -+ if blah: -+ print("+++++ names_epilogue +++++", file=f) -+ print("_all_sheets_map", REPR(self._all_sheets_map), file=f) -+ print("_extnsht_name_from_num", REPR(self._extnsht_name_from_num), file=f) -+ print("_sheet_num_from_name", REPR(self._sheet_num_from_name), file=f) -+ num_names = len(self.name_obj_list) -+ for namex in range(num_names): -+ nobj = self.name_obj_list[namex] -+ # Convert from excel_sheet_index to scope. -+ # This is done here because in BIFF7 and earlier, the -+ # BOUNDSHEET records (from which _all_sheets_map is derived) -+ # come after the NAME records. -+ if self.biff_version >= 80: -+ sheet_index = nobj.excel_sheet_index -+ if sheet_index == 0: -+ intl_sheet_index = -1 # global -+ elif 1 <= sheet_index <= len(self._all_sheets_map): -+ intl_sheet_index = self._all_sheets_map[sheet_index-1] -+ if intl_sheet_index == -1: # maps to a macro or VBA sheet -+ intl_sheet_index = -2 # valid sheet reference but not useful -+ else: -+ # huh? -+ intl_sheet_index = -3 # invalid -+ elif 50 <= self.biff_version <= 70: -+ sheet_index = nobj.extn_sheet_num -+ if sheet_index == 0: -+ intl_sheet_index = -1 # global -+ else: -+ sheet_name = self._extnsht_name_from_num[sheet_index] -+ intl_sheet_index = self._sheet_num_from_name.get(sheet_name, -2) -+ nobj.scope = intl_sheet_index -+ -+ for namex in range(num_names): -+ nobj = self.name_obj_list[namex] -+ # Parse the formula ... -+ if nobj.macro or nobj.binary: continue -+ if nobj.evaluated: continue -+ evaluate_name_formula(self, nobj, namex, blah=blah) -+ -+ if self.verbosity >= 2: -+ print("---------- name object dump ----------", file=f) -+ for namex in range(num_names): -+ nobj = self.name_obj_list[namex] -+ nobj.dump(f, header="--- name[%d] ---" % namex) -+ print("--------------------------------------", file=f) -+ # -+ # Build some dicts for access to the name objects -+ # -+ name_and_scope_map = {} # (name.lower(), scope): Name_object -+ name_map = {} # name.lower() : list of Name_objects (sorted in scope order) -+ for namex in range(num_names): -+ nobj = self.name_obj_list[namex] -+ name_lcase = nobj.name.lower() -+ key = (name_lcase, nobj.scope) -+ if key in name_and_scope_map and self.verbosity: -+ fprintf(f, 'Duplicate entry %r in name_and_scope_map\n', key) -+ name_and_scope_map[key] = nobj -+ sort_data = (nobj.scope, namex, nobj) -+ # namex (a temp unique ID) ensures the Name objects will not -+ # be compared (fatal in py3) -+ if name_lcase in name_map: -+ name_map[name_lcase].append(sort_data) -+ else: -+ name_map[name_lcase] = [sort_data] -+ for key in name_map.keys(): -+ alist = name_map[key] -+ alist.sort() -+ name_map[key] = [x[2] for x in alist] -+ self.name_and_scope_map = name_and_scope_map -+ self.name_map = name_map -+ -+ def handle_obj(self, data): -+ # Not doing much handling at all. -+ # Worrying about embedded (BOF ... EOF) substreams is done elsewhere. -+ # DEBUG = 1 -+ obj_type, obj_id = unpack(' handle_obj type=%d id=0x%08x" % (obj_type, obj_id) -+ -+ def handle_supbook(self, data): -+ # aka EXTERNALBOOK in OOo docs -+ self._supbook_types.append(None) -+ blah = DEBUG or self.verbosity >= 2 -+ if blah: -+ print("SUPBOOK:", file=self.logfile) -+ hex_char_dump(data, 0, len(data), fout=self.logfile) -+ num_sheets = unpack("= 2: -+ fprintf(self.logfile, "SST: unique strings: %d\n", uniquestrings) -+ while 1: -+ code, nb, data = self.get_record_parts_conditional(XL_CONTINUE) -+ if code is None: -+ break -+ nbt += nb -+ if DEBUG >= 2: -+ fprintf(self.logfile, "CONTINUE: adding %d bytes to SST -> %d\n", nb, nbt) -+ strlist.append(data) -+ self._sharedstrings, rt_runlist = unpack_SST_table(strlist, uniquestrings) -+ if self.formatting_info: -+ self._rich_text_runlist_map = rt_runlist -+ if DEBUG: -+ t1 = time.time() -+ print("SST processing took %.2f seconds" % (t1 - t0, ), file=self.logfile) -+ -+ def handle_writeaccess(self, data): -+ DEBUG = 0 -+ if self.biff_version < 80: -+ if not self.encoding: -+ self.raw_user_name = True -+ self.user_name = data -+ return -+ strg = unpack_string(data, 0, self.encoding, lenlen=1) -+ else: -+ strg = unpack_unicode(data, 0, lenlen=2) -+ if DEBUG: fprintf(self.logfile, "WRITEACCESS: %d bytes; raw=%s %r\n", len(data), self.raw_user_name, strg) -+ strg = strg.rstrip() -+ self.user_name = strg -+ -+ def parse_globals(self): -+ # DEBUG = 0 -+ # no need to position, just start reading (after the BOF) -+ formatting.initialise_book(self) -+ while 1: -+ rc, length, data = self.get_record_parts() -+ if DEBUG: print("parse_globals: record code is 0x%04x" % rc, file=self.logfile) -+ if rc == XL_SST: -+ self.handle_sst(data) -+ elif rc == XL_FONT or rc == XL_FONT_B3B4: -+ self.handle_font(data) -+ elif rc == XL_FORMAT: # XL_FORMAT2 is BIFF <= 3.0, can't appear in globals -+ self.handle_format(data) -+ elif rc == XL_XF: -+ self.handle_xf(data) -+ elif rc == XL_BOUNDSHEET: -+ self.handle_boundsheet(data) -+ elif rc == XL_DATEMODE: -+ self.handle_datemode(data) -+ elif rc == XL_CODEPAGE: -+ self.handle_codepage(data) -+ elif rc == XL_COUNTRY: -+ self.handle_country(data) -+ elif rc == XL_EXTERNNAME: -+ self.handle_externname(data) -+ elif rc == XL_EXTERNSHEET: -+ self.handle_externsheet(data) -+ elif rc == XL_FILEPASS: -+ self.handle_filepass(data) -+ elif rc == XL_WRITEACCESS: -+ self.handle_writeaccess(data) -+ elif rc == XL_SHEETSOFFSET: -+ self.handle_sheetsoffset(data) -+ elif rc == XL_SHEETHDR: -+ self.handle_sheethdr(data) -+ elif rc == XL_SUPBOOK: -+ self.handle_supbook(data) -+ elif rc == XL_NAME: -+ self.handle_name(data) -+ elif rc == XL_PALETTE: -+ self.handle_palette(data) -+ elif rc == XL_STYLE: -+ self.handle_style(data) -+ elif rc & 0xff == 9 and self.verbosity: -+ fprintf(self.logfile, "*** Unexpected BOF at posn %d: 0x%04x len=%d data=%r\n", -+ self._position - length - 4, rc, length, data) -+ elif rc == XL_EOF: -+ self.xf_epilogue() -+ self.names_epilogue() -+ self.palette_epilogue() -+ if not self.encoding: -+ self.derive_encoding() -+ if self.biff_version == 45: -+ # DEBUG = 0 -+ if DEBUG: print("global EOF: position", self._position, file=self.logfile) -+ # if DEBUG: -+ # pos = self._position - 4 -+ # print repr(self.mem[pos:pos+40]) -+ return -+ else: -+ # if DEBUG: -+ # print >> self.logfile, "parse_globals: ignoring record code 0x%04x" % rc -+ pass -+ -+ def read(self, pos, length): -+ data = self.mem[pos:pos+length] -+ self._position = pos + len(data) -+ return data -+ -+ def getbof(self, rqd_stream): -+ # DEBUG = 1 -+ # if DEBUG: print >> self.logfile, "getbof(): position", self._position -+ if DEBUG: print("reqd: 0x%04x" % rqd_stream, file=self.logfile) -+ def bof_error(msg): -+ raise XLRDError('Unsupported format, or corrupt file: ' + msg) -+ savpos = self._position -+ opcode = self.get2bytes() -+ if opcode == MY_EOF: -+ bof_error('Expected BOF record; met end of file') -+ if opcode not in bofcodes: -+ bof_error('Expected BOF record; found %r' % self.mem[savpos:savpos+8]) -+ length = self.get2bytes() -+ if length == MY_EOF: -+ bof_error('Incomplete BOF record[1]; met end of file') -+ if not (4 <= length <= 20): -+ bof_error( -+ 'Invalid length (%d) for BOF record type 0x%04x' -+ % (length, opcode)) -+ padding = b'\0' * max(0, boflen[opcode] - length) -+ data = self.read(self._position, length); -+ if DEBUG: fprintf(self.logfile, "\ngetbof(): data=%r\n", data) -+ if len(data) < length: -+ bof_error('Incomplete BOF record[2]; met end of file') -+ data += padding -+ version1 = opcode >> 8 -+ version2, streamtype = unpack('= 2: -+ print("BOF: op=0x%04x vers=0x%04x stream=0x%04x buildid=%d buildyr=%d -> BIFF%d" \ -+ % (opcode, version2, streamtype, build, year, version), file=self.logfile) -+ got_globals = streamtype == XL_WORKBOOK_GLOBALS or ( -+ version == 45 and streamtype == XL_WORKBOOK_GLOBALS_4W) -+ if (rqd_stream == XL_WORKBOOK_GLOBALS and got_globals) or streamtype == rqd_stream: -+ return version -+ if version < 50 and streamtype == XL_WORKSHEET: -+ return version -+ if version >= 50 and streamtype == 0x0100: -+ bof_error("Workspace file -- no spreadsheet data") -+ bof_error( -+ 'BOF not workbook/worksheet: op=0x%04x vers=0x%04x strm=0x%04x build=%d year=%d -> BIFF%d' \ -+ % (opcode, version2, streamtype, build, year, version) -+ ) -+ -+# === helper functions -+ -+def expand_cell_address(inrow, incol): -+ # Ref : OOo docs, "4.3.4 Cell Addresses in BIFF8" -+ outrow = inrow -+ if incol & 0x8000: -+ if outrow >= 32768: -+ outrow -= 65536 -+ relrow = 1 -+ else: -+ relrow = 0 -+ outcol = incol & 0xFF -+ if incol & 0x4000: -+ if outcol >= 128: -+ outcol -= 256 -+ relcol = 1 -+ else: -+ relcol = 0 -+ return outrow, outcol, relrow, relcol -+ -+def colname(colx, _A2Z="ABCDEFGHIJKLMNOPQRSTUVWXYZ"): -+ assert colx >= 0 -+ name = UNICODE_LITERAL('') -+ while 1: -+ quot, rem = divmod(colx, 26) -+ name = _A2Z[rem] + name -+ if not quot: -+ return name -+ colx = quot - 1 -+ -+def display_cell_address(rowx, colx, relrow, relcol): -+ if relrow: -+ rowpart = "(*%s%d)" % ("+-"[rowx < 0], abs(rowx)) -+ else: -+ rowpart = "$%d" % (rowx+1,) -+ if relcol: -+ colpart = "(*%s%d)" % ("+-"[colx < 0], abs(colx)) -+ else: -+ colpart = "$" + colname(colx) -+ return colpart + rowpart -+ -+def unpack_SST_table(datatab, nstrings): -+ "Return list of strings" -+ datainx = 0 -+ ndatas = len(datatab) -+ data = datatab[0] -+ datalen = len(data) -+ pos = 8 -+ strings = [] -+ strappend = strings.append -+ richtext_runs = {} -+ local_unpack = unpack -+ local_min = min -+ local_BYTES_ORD = BYTES_ORD -+ latin_1 = "latin_1" -+ for _unused_i in xrange(nstrings): -+ nchars = local_unpack('> 1, charsneed) -+ rawstrg = data[pos:pos+2*charsavail] -+ # if DEBUG: print "SST U16: nchars=%d pos=%d rawstrg=%r" % (nchars, pos, rawstrg) -+ try: -+ accstrg += unicode(rawstrg, "utf_16_le") -+ except: -+ # print "SST U16: nchars=%d pos=%d rawstrg=%r" % (nchars, pos, rawstrg) -+ # Probable cause: dodgy data e.g. unfinished surrogate pair. -+ # E.g. file unicode2.xls in pyExcelerator's examples has cells containing -+ # unichr(i) for i in range(0x100000) -+ # so this will include 0xD800 etc -+ raise -+ pos += 2*charsavail -+ else: -+ # Note: this is COMPRESSED (not ASCII!) encoding!!! -+ charsavail = local_min(datalen - pos, charsneed) -+ rawstrg = data[pos:pos+charsavail] -+ # if DEBUG: print "SST CMPRSD: nchars=%d pos=%d rawstrg=%r" % (nchars, pos, rawstrg) -+ accstrg += unicode(rawstrg, latin_1) -+ pos += charsavail -+ charsgot += charsavail -+ if charsgot == nchars: -+ break -+ datainx += 1 -+ data = datatab[datainx] -+ datalen = len(data) -+ options = local_BYTES_ORD(data[0]) -+ pos = 1 -+ -+ if rtcount: -+ runs = [] -+ for runindex in xrange(rtcount): -+ if pos == datalen: -+ pos = 0 -+ datainx += 1 -+ data = datatab[datainx] -+ datalen = len(data) -+ runs.append(local_unpack("= datalen: -+ # adjust to correct position in next record -+ pos = pos - datalen -+ datainx += 1 -+ if datainx < ndatas: -+ data = datatab[datainx] -+ datalen = len(data) -+ else: -+ assert _unused_i == nstrings - 1 -+ strappend(accstrg) -+ return strings, richtext_runs -diff --git a/webhub/xlrd/book.pyc b/webhub/xlrd/book.pyc -new file mode 100644 -index 0000000..2feb189 -Binary files /dev/null and b/webhub/xlrd/book.pyc differ -diff --git a/webhub/xlrd/compdoc.py b/webhub/xlrd/compdoc.py -new file mode 100644 -index 0000000..e434e8e ---- /dev/null -+++ b/webhub/xlrd/compdoc.py -@@ -0,0 +1,473 @@ -+# -*- coding: cp1252 -*- -+ -+## -+# Implements the minimal functionality required -+# to extract a "Workbook" or "Book" stream (as one big string) -+# from an OLE2 Compound Document file. -+#

Copyright � 2005-2012 Stephen John Machin, Lingfo Pty Ltd

-+#

This module is part of the xlrd package, which is released under a BSD-style licence.

-+## -+ -+# No part of the content of this file was derived from the works of David Giffin. -+ -+# 2008-11-04 SJM Avoid assertion error when -1 used instead of -2 for first_SID of empty SCSS [Frank Hoffsuemmer] -+# 2007-09-08 SJM Warning message if sector sizes are extremely large. -+# 2007-05-07 SJM Meaningful exception instead of IndexError if a SAT (sector allocation table) is corrupted. -+# 2007-04-22 SJM Missing "<" in a struct.unpack call => can't open files on bigendian platforms. -+ -+from __future__ import print_function -+import sys -+from struct import unpack -+from .timemachine import * -+import array -+ -+## -+# Magic cookie that should appear in the first 8 bytes of the file. -+SIGNATURE = b"\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1" -+ -+EOCSID = -2 -+FREESID = -1 -+SATSID = -3 -+MSATSID = -4 -+EVILSID = -5 -+ -+class CompDocError(Exception): -+ pass -+ -+class DirNode(object): -+ -+ def __init__(self, DID, dent, DEBUG=0, logfile=sys.stdout): -+ # dent is the 128-byte directory entry -+ self.DID = DID -+ self.logfile = logfile -+ (cbufsize, self.etype, self.colour, self.left_DID, self.right_DID, -+ self.root_DID) = \ -+ unpack(' 20: # allows for 2**20 bytes i.e. 1MB -+ print("WARNING: sector size (2**%d) is preposterous; assuming 512 and continuing ..." \ -+ % ssz, file=logfile) -+ ssz = 9 -+ if sssz > ssz: -+ print("WARNING: short stream sector size (2**%d) is preposterous; assuming 64 and continuing ..." \ -+ % sssz, file=logfile) -+ sssz = 6 -+ self.sec_size = sec_size = 1 << ssz -+ self.short_sec_size = 1 << sssz -+ if self.sec_size != 512 or self.short_sec_size != 64: -+ print("@@@@ sec_size=%d short_sec_size=%d" % (self.sec_size, self.short_sec_size), file=logfile) -+ ( -+ SAT_tot_secs, self.dir_first_sec_sid, _unused, self.min_size_std_stream, -+ SSAT_first_sec_sid, SSAT_tot_secs, -+ MSATX_first_sec_sid, MSATX_tot_secs, -+ # ) = unpack(' 1: -+ print('MSATX: sid=%d (0x%08X)' % (sid, sid), file=logfile) -+ if sid >= mem_data_secs: -+ msg = "MSAT extension: accessing sector %d but only %d in file" % (sid, mem_data_secs) -+ if DEBUG > 1: -+ print(msg, file=logfile) -+ break -+ raise CompDocError(msg) -+ elif sid < 0: -+ raise CompDocError("MSAT extension: invalid sector id: %d" % sid) -+ if seen[sid]: -+ raise CompDocError("MSAT corruption: seen[%d] == %d" % (sid, seen[sid])) -+ seen[sid] = 1 -+ actual_MSATX_sectors += 1 -+ if DEBUG and actual_MSATX_sectors > expected_MSATX_sectors: -+ print("[1]===>>>", mem_data_secs, nent, SAT_sectors_reqd, expected_MSATX_sectors, actual_MSATX_sectors, file=logfile) -+ offset = 512 + sec_size * sid -+ MSAT.extend(unpack(fmt, mem[offset:offset+sec_size])) -+ sid = MSAT.pop() # last sector id is sid of next sector in the chain -+ -+ if DEBUG and actual_MSATX_sectors != expected_MSATX_sectors: -+ print("[2]===>>>", mem_data_secs, nent, SAT_sectors_reqd, expected_MSATX_sectors, actual_MSATX_sectors, file=logfile) -+ if DEBUG: -+ print("MSAT: len =", len(MSAT), file=logfile) -+ dump_list(MSAT, 10, logfile) -+ # -+ # === build the SAT === -+ # -+ self.SAT = [] -+ actual_SAT_sectors = 0 -+ dump_again = 0 -+ for msidx in xrange(len(MSAT)): -+ msid = MSAT[msidx] -+ if msid in (FREESID, EOCSID): -+ # Specification: the MSAT array may be padded with trailing FREESID entries. -+ # Toleration: a FREESID or EOCSID entry anywhere in the MSAT array will be ignored. -+ continue -+ if msid >= mem_data_secs: -+ if not trunc_warned: -+ print("WARNING *** File is truncated, or OLE2 MSAT is corrupt!!", file=logfile) -+ print("INFO: Trying to access sector %d but only %d available" \ -+ % (msid, mem_data_secs), file=logfile) -+ trunc_warned = 1 -+ MSAT[msidx] = EVILSID -+ dump_again = 1 -+ continue -+ elif msid < -2: -+ raise CompDocError("MSAT: invalid sector id: %d" % msid) -+ if seen[msid]: -+ raise CompDocError("MSAT extension corruption: seen[%d] == %d" % (msid, seen[msid])) -+ seen[msid] = 2 -+ actual_SAT_sectors += 1 -+ if DEBUG and actual_SAT_sectors > SAT_sectors_reqd: -+ print("[3]===>>>", mem_data_secs, nent, SAT_sectors_reqd, expected_MSATX_sectors, actual_MSATX_sectors, actual_SAT_sectors, msid, file=logfile) -+ offset = 512 + sec_size * msid -+ self.SAT.extend(unpack(fmt, mem[offset:offset+sec_size])) -+ -+ if DEBUG: -+ print("SAT: len =", len(self.SAT), file=logfile) -+ dump_list(self.SAT, 10, logfile) -+ # print >> logfile, "SAT ", -+ # for i, s in enumerate(self.SAT): -+ # print >> logfile, "entry: %4d offset: %6d, next entry: %4d" % (i, 512 + sec_size * i, s) -+ # print >> logfile, "%d:%d " % (i, s), -+ print(file=logfile) -+ if DEBUG and dump_again: -+ print("MSAT: len =", len(MSAT), file=logfile) -+ dump_list(MSAT, 10, logfile) -+ for satx in xrange(mem_data_secs, len(self.SAT)): -+ self.SAT[satx] = EVILSID -+ print("SAT: len =", len(self.SAT), file=logfile) -+ dump_list(self.SAT, 10, logfile) -+ # -+ # === build the directory === -+ # -+ dbytes = self._get_stream( -+ self.mem, 512, self.SAT, self.sec_size, self.dir_first_sec_sid, -+ name="directory", seen_id=3) -+ dirlist = [] -+ did = -1 -+ for pos in xrange(0, len(dbytes), 128): -+ did += 1 -+ dirlist.append(DirNode(did, dbytes[pos:pos+128], 0, logfile)) -+ self.dirlist = dirlist -+ _build_family_tree(dirlist, 0, dirlist[0].root_DID) # and stand well back ... -+ if DEBUG: -+ for d in dirlist: -+ d.dump(DEBUG) -+ # -+ # === get the SSCS === -+ # -+ sscs_dir = self.dirlist[0] -+ assert sscs_dir.etype == 5 # root entry -+ if sscs_dir.first_SID < 0 or sscs_dir.tot_size == 0: -+ # Problem reported by Frank Hoffsuemmer: some software was -+ # writing -1 instead of -2 (EOCSID) for the first_SID -+ # when the SCCS was empty. Not having EOCSID caused assertion -+ # failure in _get_stream. -+ # Solution: avoid calling _get_stream in any case when the -+ # SCSS appears to be empty. -+ self.SSCS = "" -+ else: -+ self.SSCS = self._get_stream( -+ self.mem, 512, self.SAT, sec_size, sscs_dir.first_SID, -+ sscs_dir.tot_size, name="SSCS", seen_id=4) -+ # if DEBUG: print >> logfile, "SSCS", repr(self.SSCS) -+ # -+ # === build the SSAT === -+ # -+ self.SSAT = [] -+ if SSAT_tot_secs > 0 and sscs_dir.tot_size == 0: -+ print("WARNING *** OLE2 inconsistency: SSCS size is 0 but SSAT size is non-zero", file=logfile) -+ if sscs_dir.tot_size > 0: -+ sid = SSAT_first_sec_sid -+ nsecs = SSAT_tot_secs -+ while sid >= 0 and nsecs > 0: -+ if seen[sid]: -+ raise CompDocError("SSAT corruption: seen[%d] == %d" % (sid, seen[sid])) -+ seen[sid] = 5 -+ nsecs -= 1 -+ start_pos = 512 + sid * sec_size -+ news = list(unpack(fmt, mem[start_pos:start_pos+sec_size])) -+ self.SSAT.extend(news) -+ sid = self.SAT[sid] -+ if DEBUG: print("SSAT last sid %d; remaining sectors %d" % (sid, nsecs), file=logfile) -+ assert nsecs == 0 and sid == EOCSID -+ if DEBUG: -+ print("SSAT", file=logfile) -+ dump_list(self.SSAT, 10, logfile) -+ if DEBUG: -+ print("seen", file=logfile) -+ dump_list(seen, 20, logfile) -+ -+ def _get_stream(self, mem, base, sat, sec_size, start_sid, size=None, name='', seen_id=None): -+ # print >> self.logfile, "_get_stream", base, sec_size, start_sid, size -+ sectors = [] -+ s = start_sid -+ if size is None: -+ # nothing to check against -+ while s >= 0: -+ if seen_id is not None: -+ if self.seen[s]: -+ raise CompDocError("%s corruption: seen[%d] == %d" % (name, s, self.seen[s])) -+ self.seen[s] = seen_id -+ start_pos = base + s * sec_size -+ sectors.append(mem[start_pos:start_pos+sec_size]) -+ try: -+ s = sat[s] -+ except IndexError: -+ raise CompDocError( -+ "OLE2 stream %r: sector allocation table invalid entry (%d)" % -+ (name, s) -+ ) -+ assert s == EOCSID -+ else: -+ todo = size -+ while s >= 0: -+ if seen_id is not None: -+ if self.seen[s]: -+ raise CompDocError("%s corruption: seen[%d] == %d" % (name, s, self.seen[s])) -+ self.seen[s] = seen_id -+ start_pos = base + s * sec_size -+ grab = sec_size -+ if grab > todo: -+ grab = todo -+ todo -= grab -+ sectors.append(mem[start_pos:start_pos+grab]) -+ try: -+ s = sat[s] -+ except IndexError: -+ raise CompDocError( -+ "OLE2 stream %r: sector allocation table invalid entry (%d)" % -+ (name, s) -+ ) -+ assert s == EOCSID -+ if todo != 0: -+ fprintf(self.logfile, -+ "WARNING *** OLE2 stream %r: expected size %d, actual size %d\n", -+ name, size, size - todo) -+ -+ return b''.join(sectors) -+ -+ def _dir_search(self, path, storage_DID=0): -+ # Return matching DirNode instance, or None -+ head = path[0] -+ tail = path[1:] -+ dl = self.dirlist -+ for child in dl[storage_DID].children: -+ if dl[child].name.lower() == head.lower(): -+ et = dl[child].etype -+ if et == 2: -+ return dl[child] -+ if et == 1: -+ if not tail: -+ raise CompDocError("Requested component is a 'storage'") -+ return self._dir_search(tail, child) -+ dl[child].dump(1) -+ raise CompDocError("Requested stream is not a 'user stream'") -+ return None -+ -+ ## -+ # Interrogate the compound document's directory; return the stream as a string if found, otherwise -+ # return None. -+ # @param qname Name of the desired stream e.g. u'Workbook'. Should be in Unicode or convertible thereto. -+ -+ def get_named_stream(self, qname): -+ d = self._dir_search(qname.split("/")) -+ if d is None: -+ return None -+ if d.tot_size >= self.min_size_std_stream: -+ return self._get_stream( -+ self.mem, 512, self.SAT, self.sec_size, d.first_SID, -+ d.tot_size, name=qname, seen_id=d.DID+6) -+ else: -+ return self._get_stream( -+ self.SSCS, 0, self.SSAT, self.short_sec_size, d.first_SID, -+ d.tot_size, name=qname + " (from SSCS)", seen_id=None) -+ -+ ## -+ # Interrogate the compound document's directory. -+ # If the named stream is not found, (None, 0, 0) will be returned. -+ # If the named stream is found and is contiguous within the original byte sequence ("mem") -+ # used when the document was opened, -+ # then (mem, offset_to_start_of_stream, length_of_stream) is returned. -+ # Otherwise a new string is built from the fragments and (new_string, 0, length_of_stream) is returned. -+ # @param qname Name of the desired stream e.g. u'Workbook'. Should be in Unicode or convertible thereto. -+ -+ def locate_named_stream(self, qname): -+ d = self._dir_search(qname.split("/")) -+ if d is None: -+ return (None, 0, 0) -+ if d.tot_size > self.mem_data_len: -+ raise CompDocError("%r stream length (%d bytes) > file data size (%d bytes)" -+ % (qname, d.tot_size, self.mem_data_len)) -+ if d.tot_size >= self.min_size_std_stream: -+ result = self._locate_stream( -+ self.mem, 512, self.SAT, self.sec_size, d.first_SID, -+ d.tot_size, qname, d.DID+6) -+ if self.DEBUG: -+ print("\nseen", file=self.logfile) -+ dump_list(self.seen, 20, self.logfile) -+ return result -+ else: -+ return ( -+ self._get_stream( -+ self.SSCS, 0, self.SSAT, self.short_sec_size, d.first_SID, -+ d.tot_size, qname + " (from SSCS)", None), -+ 0, -+ d.tot_size -+ ) -+ -+ def _locate_stream(self, mem, base, sat, sec_size, start_sid, expected_stream_size, qname, seen_id): -+ # print >> self.logfile, "_locate_stream", base, sec_size, start_sid, expected_stream_size -+ s = start_sid -+ if s < 0: -+ raise CompDocError("_locate_stream: start_sid (%d) is -ve" % start_sid) -+ p = -99 # dummy previous SID -+ start_pos = -9999 -+ end_pos = -8888 -+ slices = [] -+ tot_found = 0 -+ found_limit = (expected_stream_size + sec_size - 1) // sec_size -+ while s >= 0: -+ if self.seen[s]: -+ print("_locate_stream(%s): seen" % qname, file=self.logfile); dump_list(self.seen, 20, self.logfile) -+ raise CompDocError("%s corruption: seen[%d] == %d" % (qname, s, self.seen[s])) -+ self.seen[s] = seen_id -+ tot_found += 1 -+ if tot_found > found_limit: -+ raise CompDocError( -+ "%s: size exceeds expected %d bytes; corrupt?" -+ % (qname, found_limit * sec_size) -+ ) # Note: expected size rounded up to higher sector -+ if s == p+1: -+ # contiguous sectors -+ end_pos += sec_size -+ else: -+ # start new slice -+ if p >= 0: -+ # not first time -+ slices.append((start_pos, end_pos)) -+ start_pos = base + s * sec_size -+ end_pos = start_pos + sec_size -+ p = s -+ s = sat[s] -+ assert s == EOCSID -+ assert tot_found == found_limit -+ # print >> self.logfile, "_locate_stream(%s): seen" % qname; dump_list(self.seen, 20, self.logfile) -+ if not slices: -+ # The stream is contiguous ... just what we like! -+ return (mem, start_pos, expected_stream_size) -+ slices.append((start_pos, end_pos)) -+ # print >> self.logfile, "+++>>> %d fragments" % len(slices) -+ return (b''.join([mem[start_pos:end_pos] for start_pos, end_pos in slices]), 0, expected_stream_size) -+ -+# ========================================================================================== -+def x_dump_line(alist, stride, f, dpos, equal=0): -+ print("%5d%s" % (dpos, " ="[equal]), end=' ', file=f) -+ for value in alist[dpos:dpos + stride]: -+ print(str(value), end=' ', file=f) -+ print(file=f) -+ -+def dump_list(alist, stride, f=sys.stdout): -+ def _dump_line(dpos, equal=0): -+ print("%5d%s" % (dpos, " ="[equal]), end=' ', file=f) -+ for value in alist[dpos:dpos + stride]: -+ print(str(value), end=' ', file=f) -+ print(file=f) -+ pos = None -+ oldpos = None -+ for pos in xrange(0, len(alist), stride): -+ if oldpos is None: -+ _dump_line(pos) -+ oldpos = pos -+ elif alist[pos:pos+stride] != alist[oldpos:oldpos+stride]: -+ if pos - oldpos > stride: -+ _dump_line(pos - stride, equal=1) -+ _dump_line(pos) -+ oldpos = pos -+ if oldpos is not None and pos is not None and pos != oldpos: -+ _dump_line(pos, equal=1) -diff --git a/webhub/xlrd/compdoc.pyc b/webhub/xlrd/compdoc.pyc -new file mode 100644 -index 0000000..65b137d -Binary files /dev/null and b/webhub/xlrd/compdoc.pyc differ -diff --git a/webhub/xlrd/formatting.py b/webhub/xlrd/formatting.py -new file mode 100644 -index 0000000..f044915 ---- /dev/null -+++ b/webhub/xlrd/formatting.py -@@ -0,0 +1,1262 @@ -+# -*- coding: cp1252 -*- -+ -+## -+# Module for formatting information. -+# -+#

Copyright 2005-2012 Stephen John Machin, Lingfo Pty Ltd

-+#

This module is part of the xlrd package, which is released under -+# a BSD-style licence.

-+## -+ -+# No part of the content of this file was derived from the works of David Giffin. -+ -+from __future__ import print_function -+ -+DEBUG = 0 -+import re -+from struct import unpack -+from .timemachine import * -+from .biffh import BaseObject, unpack_unicode, unpack_string, \ -+ upkbits, upkbitsL, fprintf, \ -+ FUN, FDT, FNU, FGE, FTX, XL_CELL_NUMBER, XL_CELL_DATE, \ -+ XL_FORMAT, XL_FORMAT2, \ -+ XLRDError -+ -+_cellty_from_fmtty = { -+ FNU: XL_CELL_NUMBER, -+ FUN: XL_CELL_NUMBER, -+ FGE: XL_CELL_NUMBER, -+ FDT: XL_CELL_DATE, -+ FTX: XL_CELL_NUMBER, # Yes, a number can be formatted as text. -+ } -+ -+excel_default_palette_b5 = ( -+ ( 0, 0, 0), (255, 255, 255), (255, 0, 0), ( 0, 255, 0), -+ ( 0, 0, 255), (255, 255, 0), (255, 0, 255), ( 0, 255, 255), -+ (128, 0, 0), ( 0, 128, 0), ( 0, 0, 128), (128, 128, 0), -+ (128, 0, 128), ( 0, 128, 128), (192, 192, 192), (128, 128, 128), -+ (153, 153, 255), (153, 51, 102), (255, 255, 204), (204, 255, 255), -+ (102, 0, 102), (255, 128, 128), ( 0, 102, 204), (204, 204, 255), -+ ( 0, 0, 128), (255, 0, 255), (255, 255, 0), ( 0, 255, 255), -+ (128, 0, 128), (128, 0, 0), ( 0, 128, 128), ( 0, 0, 255), -+ ( 0, 204, 255), (204, 255, 255), (204, 255, 204), (255, 255, 153), -+ (153, 204, 255), (255, 153, 204), (204, 153, 255), (227, 227, 227), -+ ( 51, 102, 255), ( 51, 204, 204), (153, 204, 0), (255, 204, 0), -+ (255, 153, 0), (255, 102, 0), (102, 102, 153), (150, 150, 150), -+ ( 0, 51, 102), ( 51, 153, 102), ( 0, 51, 0), ( 51, 51, 0), -+ (153, 51, 0), (153, 51, 102), ( 51, 51, 153), ( 51, 51, 51), -+ ) -+ -+excel_default_palette_b2 = excel_default_palette_b5[:16] -+ -+# Following table borrowed from Gnumeric 1.4 source. -+# Checked against OOo docs and MS docs. -+excel_default_palette_b8 = ( # (red, green, blue) -+ ( 0, 0, 0), (255,255,255), (255, 0, 0), ( 0,255, 0), # 0 -+ ( 0, 0,255), (255,255, 0), (255, 0,255), ( 0,255,255), # 4 -+ (128, 0, 0), ( 0,128, 0), ( 0, 0,128), (128,128, 0), # 8 -+ (128, 0,128), ( 0,128,128), (192,192,192), (128,128,128), # 12 -+ (153,153,255), (153, 51,102), (255,255,204), (204,255,255), # 16 -+ (102, 0,102), (255,128,128), ( 0,102,204), (204,204,255), # 20 -+ ( 0, 0,128), (255, 0,255), (255,255, 0), ( 0,255,255), # 24 -+ (128, 0,128), (128, 0, 0), ( 0,128,128), ( 0, 0,255), # 28 -+ ( 0,204,255), (204,255,255), (204,255,204), (255,255,153), # 32 -+ (153,204,255), (255,153,204), (204,153,255), (255,204,153), # 36 -+ ( 51,102,255), ( 51,204,204), (153,204, 0), (255,204, 0), # 40 -+ (255,153, 0), (255,102, 0), (102,102,153), (150,150,150), # 44 -+ ( 0, 51,102), ( 51,153,102), ( 0, 51, 0), ( 51, 51, 0), # 48 -+ (153, 51, 0), (153, 51,102), ( 51, 51,153), ( 51, 51, 51), # 52 -+ ) -+ -+default_palette = { -+ 80: excel_default_palette_b8, -+ 70: excel_default_palette_b5, -+ 50: excel_default_palette_b5, -+ 45: excel_default_palette_b2, -+ 40: excel_default_palette_b2, -+ 30: excel_default_palette_b2, -+ 21: excel_default_palette_b2, -+ 20: excel_default_palette_b2, -+ } -+ -+""" -+00H = Normal -+01H = RowLevel_lv (see next field) -+02H = ColLevel_lv (see next field) -+03H = Comma -+04H = Currency -+05H = Percent -+06H = Comma [0] (BIFF4-BIFF8) -+07H = Currency [0] (BIFF4-BIFF8) -+08H = Hyperlink (BIFF8) -+09H = Followed Hyperlink (BIFF8) -+""" -+built_in_style_names = [ -+ "Normal", -+ "RowLevel_", -+ "ColLevel_", -+ "Comma", -+ "Currency", -+ "Percent", -+ "Comma [0]", -+ "Currency [0]", -+ "Hyperlink", -+ "Followed Hyperlink", -+ ] -+ -+def initialise_colour_map(book): -+ book.colour_map = {} -+ book.colour_indexes_used = {} -+ if not book.formatting_info: -+ return -+ # Add the 8 invariant colours -+ for i in xrange(8): -+ book.colour_map[i] = excel_default_palette_b8[i] -+ # Add the default palette depending on the version -+ dpal = default_palette[book.biff_version] -+ ndpal = len(dpal) -+ for i in xrange(ndpal): -+ book.colour_map[i+8] = dpal[i] -+ # Add the specials -- None means the RGB value is not known -+ # System window text colour for border lines -+ book.colour_map[ndpal+8] = None -+ # System window background colour for pattern background -+ book.colour_map[ndpal+8+1] = None # -+ for ci in ( -+ 0x51, # System ToolTip text colour (used in note objects) -+ 0x7FFF, # 32767, system window text colour for fonts -+ ): -+ book.colour_map[ci] = None -+ -+def nearest_colour_index(colour_map, rgb, debug=0): -+ # General purpose function. Uses Euclidean distance. -+ # So far used only for pre-BIFF8 WINDOW2 record. -+ # Doesn't have to be fast. -+ # Doesn't have to be fancy. -+ best_metric = 3 * 256 * 256 -+ best_colourx = 0 -+ for colourx, cand_rgb in colour_map.items(): -+ if cand_rgb is None: -+ continue -+ metric = 0 -+ for v1, v2 in zip(rgb, cand_rgb): -+ metric += (v1 - v2) * (v1 - v2) -+ if metric < best_metric: -+ best_metric = metric -+ best_colourx = colourx -+ if metric == 0: -+ break -+ if 0 and debug: -+ print("nearest_colour_index for %r is %r -> %r; best_metric is %d" \ -+ % (rgb, best_colourx, colour_map[best_colourx], best_metric)) -+ return best_colourx -+ -+## -+# This mixin class exists solely so that Format, Font, and XF.... objects -+# can be compared by value of their attributes. -+class EqNeAttrs(object): -+ -+ def __eq__(self, other): -+ return self.__dict__ == other.__dict__ -+ -+ def __ne__(self, other): -+ return self.__dict__ != other.__dict__ -+ -+## -+# An Excel "font" contains the details of not only what is normally -+# considered a font, but also several other display attributes. -+# Items correspond to those in the Excel UI's Format/Cells/Font tab. -+#
-- New in version 0.6.1 -+class Font(BaseObject, EqNeAttrs): -+ ## -+ # 1 = Characters are bold. Redundant; see "weight" attribute. -+ bold = 0 -+ ## -+ # Values: 0 = ANSI Latin, 1 = System default, 2 = Symbol, -+ # 77 = Apple Roman, -+ # 128 = ANSI Japanese Shift-JIS, -+ # 129 = ANSI Korean (Hangul), -+ # 130 = ANSI Korean (Johab), -+ # 134 = ANSI Chinese Simplified GBK, -+ # 136 = ANSI Chinese Traditional BIG5, -+ # 161 = ANSI Greek, -+ # 162 = ANSI Turkish, -+ # 163 = ANSI Vietnamese, -+ # 177 = ANSI Hebrew, -+ # 178 = ANSI Arabic, -+ # 186 = ANSI Baltic, -+ # 204 = ANSI Cyrillic, -+ # 222 = ANSI Thai, -+ # 238 = ANSI Latin II (Central European), -+ # 255 = OEM Latin I -+ character_set = 0 -+ ## -+ # An explanation of "colour index" is given in the Formatting -+ # section at the start of this document. -+ colour_index = 0 -+ ## -+ # 1 = Superscript, 2 = Subscript. -+ escapement = 0 -+ ## -+ # 0 = None (unknown or don't care)
-+ # 1 = Roman (variable width, serifed)
-+ # 2 = Swiss (variable width, sans-serifed)
-+ # 3 = Modern (fixed width, serifed or sans-serifed)
-+ # 4 = Script (cursive)
-+ # 5 = Decorative (specialised, for example Old English, Fraktur) -+ family = 0 -+ ## -+ # The 0-based index used to refer to this Font() instance. -+ # Note that index 4 is never used; xlrd supplies a dummy place-holder. -+ font_index = 0 -+ ## -+ # Height of the font (in twips). A twip = 1/20 of a point. -+ height = 0 -+ ## -+ # 1 = Characters are italic. -+ italic = 0 -+ ## -+ # The name of the font. Example: u"Arial" -+ name = UNICODE_LITERAL("") -+ ## -+ # 1 = Characters are struck out. -+ struck_out = 0 -+ ## -+ # 0 = None
-+ # 1 = Single; 0x21 (33) = Single accounting
-+ # 2 = Double; 0x22 (34) = Double accounting -+ underline_type = 0 -+ ## -+ # 1 = Characters are underlined. Redundant; see "underline_type" attribute. -+ underlined = 0 -+ ## -+ # Font weight (100-1000). Standard values are 400 for normal text -+ # and 700 for bold text. -+ weight = 400 -+ ## -+ # 1 = Font is outline style (Macintosh only) -+ outline = 0 -+ ## -+ # 1 = Font is shadow style (Macintosh only) -+ shadow = 0 -+ -+ # No methods ... -+ -+def handle_efont(book, data): # BIFF2 only -+ if not book.formatting_info: -+ return -+ book.font_list[-1].colour_index = unpack('= 2 -+ bv = book.biff_version -+ k = len(book.font_list) -+ if k == 4: -+ f = Font() -+ f.name = UNICODE_LITERAL('Dummy Font') -+ f.font_index = k -+ book.font_list.append(f) -+ k += 1 -+ f = Font() -+ f.font_index = k -+ book.font_list.append(f) -+ if bv >= 50: -+ ( -+ f.height, option_flags, f.colour_index, f.weight, -+ f.escapement, f.underline_type, f.family, -+ f.character_set, -+ ) = unpack('> 1 -+ f.underlined = (option_flags & 4) >> 2 -+ f.struck_out = (option_flags & 8) >> 3 -+ f.outline = (option_flags & 16) >> 4 -+ f.shadow = (option_flags & 32) >> 5 -+ if bv >= 80: -+ f.name = unpack_unicode(data, 14, lenlen=1) -+ else: -+ f.name = unpack_string(data, 14, book.encoding, lenlen=1) -+ elif bv >= 30: -+ f.height, option_flags, f.colour_index = unpack('> 1 -+ f.underlined = (option_flags & 4) >> 2 -+ f.struck_out = (option_flags & 8) >> 3 -+ f.outline = (option_flags & 16) >> 4 -+ f.shadow = (option_flags & 32) >> 5 -+ f.name = unpack_string(data, 6, book.encoding, lenlen=1) -+ # Now cook up the remaining attributes ... -+ f.weight = [400, 700][f.bold] -+ f.escapement = 0 # None -+ f.underline_type = f.underlined # None or Single -+ f.family = 0 # Unknown / don't care -+ f.character_set = 1 # System default (0 means "ANSI Latin") -+ else: # BIFF2 -+ f.height, option_flags = unpack('> 1 -+ f.underlined = (option_flags & 4) >> 2 -+ f.struck_out = (option_flags & 8) >> 3 -+ f.outline = 0 -+ f.shadow = 0 -+ f.name = unpack_string(data, 4, book.encoding, lenlen=1) -+ # Now cook up the remaining attributes ... -+ f.weight = [400, 700][f.bold] -+ f.escapement = 0 # None -+ f.underline_type = f.underlined # None or Single -+ f.family = 0 # Unknown / don't care -+ f.character_set = 1 # System default (0 means "ANSI Latin") -+ if blah: -+ f.dump( -+ book.logfile, -+ header="--- handle_font: font[%d] ---" % f.font_index, -+ footer="-------------------", -+ ) -+ -+# === "Number formats" === -+ -+## -+# "Number format" information from a FORMAT record. -+#
-- New in version 0.6.1 -+class Format(BaseObject, EqNeAttrs): -+ ## -+ # The key into Book.format_map -+ format_key = 0 -+ ## -+ # A classification that has been inferred from the format string. -+ # Currently, this is used only to distinguish between numbers and dates. -+ #
Values: -+ #
FUN = 0 # unknown -+ #
FDT = 1 # date -+ #
FNU = 2 # number -+ #
FGE = 3 # general -+ #
FTX = 4 # text -+ type = FUN -+ ## -+ # The format string -+ format_str = UNICODE_LITERAL('') -+ -+ def __init__(self, format_key, ty, format_str): -+ self.format_key = format_key -+ self.type = ty -+ self.format_str = format_str -+ -+std_format_strings = { -+ # "std" == "standard for US English locale" -+ # #### TODO ... a lot of work to tailor these to the user's locale. -+ # See e.g. gnumeric-1.x.y/src/formats.c -+ 0x00: "General", -+ 0x01: "0", -+ 0x02: "0.00", -+ 0x03: "#,##0", -+ 0x04: "#,##0.00", -+ 0x05: "$#,##0_);($#,##0)", -+ 0x06: "$#,##0_);[Red]($#,##0)", -+ 0x07: "$#,##0.00_);($#,##0.00)", -+ 0x08: "$#,##0.00_);[Red]($#,##0.00)", -+ 0x09: "0%", -+ 0x0a: "0.00%", -+ 0x0b: "0.00E+00", -+ 0x0c: "# ?/?", -+ 0x0d: "# ??/??", -+ 0x0e: "m/d/yy", -+ 0x0f: "d-mmm-yy", -+ 0x10: "d-mmm", -+ 0x11: "mmm-yy", -+ 0x12: "h:mm AM/PM", -+ 0x13: "h:mm:ss AM/PM", -+ 0x14: "h:mm", -+ 0x15: "h:mm:ss", -+ 0x16: "m/d/yy h:mm", -+ 0x25: "#,##0_);(#,##0)", -+ 0x26: "#,##0_);[Red](#,##0)", -+ 0x27: "#,##0.00_);(#,##0.00)", -+ 0x28: "#,##0.00_);[Red](#,##0.00)", -+ 0x29: "_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(@_)", -+ 0x2a: "_($* #,##0_);_($* (#,##0);_($* \"-\"_);_(@_)", -+ 0x2b: "_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)", -+ 0x2c: "_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(@_)", -+ 0x2d: "mm:ss", -+ 0x2e: "[h]:mm:ss", -+ 0x2f: "mm:ss.0", -+ 0x30: "##0.0E+0", -+ 0x31: "@", -+ } -+ -+fmt_code_ranges = [ # both-inclusive ranges of "standard" format codes -+ # Source: the openoffice.org doc't -+ # and the OOXML spec Part 4, section 3.8.30 -+ ( 0, 0, FGE), -+ ( 1, 13, FNU), -+ (14, 22, FDT), -+ (27, 36, FDT), # CJK date formats -+ (37, 44, FNU), -+ (45, 47, FDT), -+ (48, 48, FNU), -+ (49, 49, FTX), -+ # Gnumeric assumes (or assumed) that built-in formats finish at 49, not at 163 -+ (50, 58, FDT), # CJK date formats -+ (59, 62, FNU), # Thai number (currency?) formats -+ (67, 70, FNU), # Thai number (currency?) formats -+ (71, 81, FDT), # Thai date formats -+ ] -+ -+std_format_code_types = {} -+for lo, hi, ty in fmt_code_ranges: -+ for x in xrange(lo, hi+1): -+ std_format_code_types[x] = ty -+del lo, hi, ty, x -+ -+date_chars = UNICODE_LITERAL('ymdhs') # year, month/minute, day, hour, second -+date_char_dict = {} -+for _c in date_chars + date_chars.upper(): -+ date_char_dict[_c] = 5 -+del _c, date_chars -+ -+skip_char_dict = {} -+for _c in UNICODE_LITERAL('$-+/(): '): -+ skip_char_dict[_c] = 1 -+ -+num_char_dict = { -+ UNICODE_LITERAL('0'): 5, -+ UNICODE_LITERAL('#'): 5, -+ UNICODE_LITERAL('?'): 5, -+ } -+ -+non_date_formats = { -+ UNICODE_LITERAL('0.00E+00'):1, -+ UNICODE_LITERAL('##0.0E+0'):1, -+ UNICODE_LITERAL('General') :1, -+ UNICODE_LITERAL('GENERAL') :1, # OOo Calc 1.1.4 does this. -+ UNICODE_LITERAL('general') :1, # pyExcelerator 0.6.3 does this. -+ UNICODE_LITERAL('@') :1, -+ } -+ -+fmt_bracketed_sub = re.compile(r'\[[^]]*\]').sub -+ -+# Boolean format strings (actual cases) -+# u'"Yes";"Yes";"No"' -+# u'"True";"True";"False"' -+# u'"On";"On";"Off"' -+ -+def is_date_format_string(book, fmt): -+ # Heuristics: -+ # Ignore "text" and [stuff in square brackets (aarrgghh -- see below)]. -+ # Handle backslashed-escaped chars properly. -+ # E.g. hh\hmm\mss\s should produce a display like 23h59m59s -+ # Date formats have one or more of ymdhs (caseless) in them. -+ # Numeric formats have # and 0. -+ # N.B. u'General"."' hence get rid of "text" first. -+ # TODO: Find where formats are interpreted in Gnumeric -+ # TODO: u'[h]\\ \\h\\o\\u\\r\\s' ([h] means don't care about hours > 23) -+ state = 0 -+ s = '' -+ -+ for c in fmt: -+ if state == 0: -+ if c == UNICODE_LITERAL('"'): -+ state = 1 -+ elif c in UNICODE_LITERAL(r"\_*"): -+ state = 2 -+ elif c in skip_char_dict: -+ pass -+ else: -+ s += c -+ elif state == 1: -+ if c == UNICODE_LITERAL('"'): -+ state = 0 -+ elif state == 2: -+ # Ignore char after backslash, underscore or asterisk -+ state = 0 -+ assert 0 <= state <= 2 -+ if book.verbosity >= 4: -+ print("is_date_format_string: reduced format is %s" % REPR(s), file=book.logfile) -+ s = fmt_bracketed_sub('', s) -+ if s in non_date_formats: -+ return False -+ state = 0 -+ separator = ";" -+ got_sep = 0 -+ date_count = num_count = 0 -+ for c in s: -+ if c in date_char_dict: -+ date_count += date_char_dict[c] -+ elif c in num_char_dict: -+ num_count += num_char_dict[c] -+ elif c == separator: -+ got_sep = 1 -+ # print num_count, date_count, repr(fmt) -+ if date_count and not num_count: -+ return True -+ if num_count and not date_count: -+ return False -+ if date_count: -+ if book.verbosity: -+ fprintf(book.logfile, -+ 'WARNING *** is_date_format: ambiguous d=%d n=%d fmt=%r\n', -+ date_count, num_count, fmt) -+ elif not got_sep: -+ if book.verbosity: -+ fprintf(book.logfile, -+ "WARNING *** format %r produces constant result\n", -+ fmt) -+ return date_count > num_count -+ -+def handle_format(self, data, rectype=XL_FORMAT): -+ DEBUG = 0 -+ bv = self.biff_version -+ if rectype == XL_FORMAT2: -+ bv = min(bv, 30) -+ if not self.encoding: -+ self.derive_encoding() -+ strpos = 2 -+ if bv >= 50: -+ fmtkey = unpack('= 80: -+ unistrg = unpack_unicode(data, 2) -+ else: -+ unistrg = unpack_string(data, strpos, self.encoding, lenlen=1) -+ blah = DEBUG or self.verbosity >= 3 -+ if blah: -+ fprintf(self.logfile, -+ "FORMAT: count=%d fmtkey=0x%04x (%d) s=%r\n", -+ self.actualfmtcount, fmtkey, fmtkey, unistrg) -+ is_date_s = self.is_date_format_string(unistrg) -+ ty = [FGE, FDT][is_date_s] -+ if not(fmtkey > 163 or bv < 50): -+ # user_defined if fmtkey > 163 -+ # N.B. Gnumeric incorrectly starts these at 50 instead of 164 :-( -+ # if earlier than BIFF 5, standard info is useless -+ std_ty = std_format_code_types.get(fmtkey, FUN) -+ # print "std ty", std_ty -+ is_date_c = std_ty == FDT -+ if self.verbosity and 0 < fmtkey < 50 and (is_date_c ^ is_date_s): -+ DEBUG = 2 -+ fprintf(self.logfile, -+ "WARNING *** Conflict between " -+ "std format key %d and its format string %r\n", -+ fmtkey, unistrg) -+ if DEBUG == 2: -+ fprintf(self.logfile, -+ "ty: %d; is_date_c: %r; is_date_s: %r; fmt_strg: %r", -+ ty, is_date_c, is_date_s, unistrg) -+ fmtobj = Format(fmtkey, ty, unistrg) -+ if blah: -+ fmtobj.dump(self.logfile, -+ header="--- handle_format [%d] ---" % (self.actualfmtcount-1, )) -+ self.format_map[fmtkey] = fmtobj -+ self.format_list.append(fmtobj) -+ -+# ============================================================================= -+ -+def handle_palette(book, data): -+ if not book.formatting_info: -+ return -+ blah = DEBUG or book.verbosity >= 2 -+ n_colours, = unpack('= 50] -+ if ((DEBUG or book.verbosity >= 1) -+ and n_colours != expected_n_colours): -+ fprintf(book.logfile, -+ "NOTE *** Expected %d colours in PALETTE record, found %d\n", -+ expected_n_colours, n_colours) -+ elif blah: -+ fprintf(book.logfile, -+ "PALETTE record with %d colours\n", n_colours) -+ fmt = '> 8) & 0xff -+ blue = (c >> 16) & 0xff -+ old_rgb = book.colour_map[8+i] -+ new_rgb = (red, green, blue) -+ book.palette_record.append(new_rgb) -+ book.colour_map[8+i] = new_rgb -+ if blah: -+ if new_rgb != old_rgb: -+ print("%2d: %r -> %r" % (i, old_rgb, new_rgb), file=book.logfile) -+ -+def palette_epilogue(book): -+ # Check colour indexes in fonts etc. -+ # This must be done here as FONT records -+ # come *before* the PALETTE record :-( -+ for font in book.font_list: -+ if font.font_index == 4: # the missing font record -+ continue -+ cx = font.colour_index -+ if cx == 0x7fff: # system window text colour -+ continue -+ if cx in book.colour_map: -+ book.colour_indexes_used[cx] = 1 -+ elif book.verbosity: -+ print("Size of colour table:", len(book.colour_map), file=book.logfile) -+ fprintf(book.logfile, "*** Font #%d (%r): colour index 0x%04x is unknown\n", -+ font.font_index, font.name, cx) -+ if book.verbosity >= 1: -+ used = sorted(book.colour_indexes_used.keys()) -+ print("\nColour indexes used:\n%r\n" % used, file=book.logfile) -+ -+def handle_style(book, data): -+ if not book.formatting_info: -+ return -+ blah = DEBUG or book.verbosity >= 2 -+ bv = book.biff_version -+ flag_and_xfx, built_in_id, level = unpack('= 80: -+ try: -+ name = unpack_unicode(data, 2, lenlen=2) -+ except UnicodeDecodeError: -+ print("STYLE: built_in=%d xf_index=%d built_in_id=%d level=%d" \ -+ % (built_in, xf_index, built_in_id, level), file=book.logfile) -+ print("raw bytes:", repr(data[2:]), file=book.logfile) -+ raise -+ else: -+ name = unpack_string(data, 2, book.encoding, lenlen=1) -+ if blah and not name: -+ print("WARNING *** A user-defined style has a zero-length name", file=book.logfile) -+ book.style_name_map[name] = (built_in, xf_index) -+ if blah: -+ fprintf(book.logfile, "STYLE: built_in=%d xf_index=%d built_in_id=%d level=%d name=%r\n", -+ built_in, xf_index, built_in_id, level, name) -+ -+def check_colour_indexes_in_obj(book, obj, orig_index): -+ alist = sorted(obj.__dict__.items()) -+ for attr, nobj in alist: -+ if hasattr(nobj, 'dump'): -+ check_colour_indexes_in_obj(book, nobj, orig_index) -+ elif attr.find('colour_index') >= 0: -+ if nobj in book.colour_map: -+ book.colour_indexes_used[nobj] = 1 -+ continue -+ oname = obj.__class__.__name__ -+ print("*** xf #%d : %s.%s = 0x%04x (unknown)" \ -+ % (orig_index, oname, attr, nobj), file=book.logfile) -+ -+def fill_in_standard_formats(book): -+ for x in std_format_code_types.keys(): -+ if x not in book.format_map: -+ ty = std_format_code_types[x] -+ # Note: many standard format codes (mostly CJK date formats) have -+ # format strings that vary by locale; xlrd does not (yet) -+ # handle those; the type (date or numeric) is recorded but the fmt_str will be None. -+ fmt_str = std_format_strings.get(x) -+ fmtobj = Format(x, ty, fmt_str) -+ book.format_map[x] = fmtobj -+ -+def handle_xf(self, data): -+ ### self is a Book instance -+ # DEBUG = 0 -+ blah = DEBUG or self.verbosity >= 3 -+ bv = self.biff_version -+ xf = XF() -+ xf.alignment = XFAlignment() -+ xf.alignment.indent_level = 0 -+ xf.alignment.shrink_to_fit = 0 -+ xf.alignment.text_direction = 0 -+ xf.border = XFBorder() -+ xf.border.diag_up = 0 -+ xf.border.diag_down = 0 -+ xf.border.diag_colour_index = 0 -+ xf.border.diag_line_style = 0 # no line -+ xf.background = XFBackground() -+ xf.protection = XFProtection() -+ # fill in the known standard formats -+ if bv >= 50 and not self.xfcount: -+ # i.e. do this once before we process the first XF record -+ fill_in_standard_formats(self) -+ if bv >= 80: -+ unpack_fmt = '> 2 -+ for attr_stem in \ -+ "format font alignment border background protection".split(): -+ attr = "_" + attr_stem + "_flag" -+ setattr(xf, attr, reg & 1) -+ reg >>= 1 -+ upkbitsL(xf.border, pkd_brdbkg1, ( -+ (0, 0x0000000f, 'left_line_style'), -+ (4, 0x000000f0, 'right_line_style'), -+ (8, 0x00000f00, 'top_line_style'), -+ (12, 0x0000f000, 'bottom_line_style'), -+ (16, 0x007f0000, 'left_colour_index'), -+ (23, 0x3f800000, 'right_colour_index'), -+ (30, 0x40000000, 'diag_down'), -+ (31, 0x80000000, 'diag_up'), -+ )) -+ upkbits(xf.border, pkd_brdbkg2, ( -+ (0, 0x0000007F, 'top_colour_index'), -+ (7, 0x00003F80, 'bottom_colour_index'), -+ (14, 0x001FC000, 'diag_colour_index'), -+ (21, 0x01E00000, 'diag_line_style'), -+ )) -+ upkbitsL(xf.background, pkd_brdbkg2, ( -+ (26, 0xFC000000, 'fill_pattern'), -+ )) -+ upkbits(xf.background, pkd_brdbkg3, ( -+ (0, 0x007F, 'pattern_colour_index'), -+ (7, 0x3F80, 'background_colour_index'), -+ )) -+ elif bv >= 50: -+ unpack_fmt = '> 2 -+ for attr_stem in \ -+ "format font alignment border background protection".split(): -+ attr = "_" + attr_stem + "_flag" -+ setattr(xf, attr, reg & 1) -+ reg >>= 1 -+ upkbitsL(xf.background, pkd_brdbkg1, ( -+ ( 0, 0x0000007F, 'pattern_colour_index'), -+ ( 7, 0x00003F80, 'background_colour_index'), -+ (16, 0x003F0000, 'fill_pattern'), -+ )) -+ upkbitsL(xf.border, pkd_brdbkg1, ( -+ (22, 0x01C00000, 'bottom_line_style'), -+ (25, 0xFE000000, 'bottom_colour_index'), -+ )) -+ upkbits(xf.border, pkd_brdbkg2, ( -+ ( 0, 0x00000007, 'top_line_style'), -+ ( 3, 0x00000038, 'left_line_style'), -+ ( 6, 0x000001C0, 'right_line_style'), -+ ( 9, 0x0000FE00, 'top_colour_index'), -+ (16, 0x007F0000, 'left_colour_index'), -+ (23, 0x3F800000, 'right_colour_index'), -+ )) -+ elif bv >= 40: -+ unpack_fmt = '> 6 -+ xf.alignment.rotation = [0, 255, 90, 180][orientation] -+ reg = pkd_used >> 2 -+ for attr_stem in \ -+ "format font alignment border background protection".split(): -+ attr = "_" + attr_stem + "_flag" -+ setattr(xf, attr, reg & 1) -+ reg >>= 1 -+ upkbits(xf.background, pkd_bkg_34, ( -+ ( 0, 0x003F, 'fill_pattern'), -+ ( 6, 0x07C0, 'pattern_colour_index'), -+ (11, 0xF800, 'background_colour_index'), -+ )) -+ upkbitsL(xf.border, pkd_brd_34, ( -+ ( 0, 0x00000007, 'top_line_style'), -+ ( 3, 0x000000F8, 'top_colour_index'), -+ ( 8, 0x00000700, 'left_line_style'), -+ (11, 0x0000F800, 'left_colour_index'), -+ (16, 0x00070000, 'bottom_line_style'), -+ (19, 0x00F80000, 'bottom_colour_index'), -+ (24, 0x07000000, 'right_line_style'), -+ (27, 0xF8000000, 'right_colour_index'), -+ )) -+ elif bv == 30: -+ unpack_fmt = '> 2 -+ for attr_stem in \ -+ "format font alignment border background protection".split(): -+ attr = "_" + attr_stem + "_flag" -+ setattr(xf, attr, reg & 1) -+ reg >>= 1 -+ upkbits(xf.background, pkd_bkg_34, ( -+ ( 0, 0x003F, 'fill_pattern'), -+ ( 6, 0x07C0, 'pattern_colour_index'), -+ (11, 0xF800, 'background_colour_index'), -+ )) -+ upkbitsL(xf.border, pkd_brd_34, ( -+ ( 0, 0x00000007, 'top_line_style'), -+ ( 3, 0x000000F8, 'top_colour_index'), -+ ( 8, 0x00000700, 'left_line_style'), -+ (11, 0x0000F800, 'left_colour_index'), -+ (16, 0x00070000, 'bottom_line_style'), -+ (19, 0x00F80000, 'bottom_colour_index'), -+ (24, 0x07000000, 'right_line_style'), -+ (27, 0xF8000000, 'right_colour_index'), -+ )) -+ xf.alignment.vert_align = 2 # bottom -+ xf.alignment.rotation = 0 -+ elif bv == 21: -+ #### Warning: incomplete treatment; formatting_info not fully supported. -+ #### Probably need to offset incoming BIFF2 XF[n] to BIFF8-like XF[n+16], -+ #### and create XF[0:16] like the standard ones in BIFF8 -+ #### *AND* add 16 to all XF references in cell records :-( -+ (xf.font_index, format_etc, halign_etc) = unpack('= 3 -+ blah1 = DEBUG or self.verbosity >= 1 -+ if blah: -+ fprintf(self.logfile, "xf_epilogue called ...\n") -+ -+ def check_same(book_arg, xf_arg, parent_arg, attr): -+ # the _arg caper is to avoid a Warning msg from Python 2.1 :-( -+ if getattr(xf_arg, attr) != getattr(parent_arg, attr): -+ fprintf(book_arg.logfile, -+ "NOTE !!! XF[%d] parent[%d] %s different\n", -+ xf_arg.xf_index, parent_arg.xf_index, attr) -+ -+ for xfx in xrange(num_xfs): -+ xf = self.xf_list[xfx] -+ if xf.format_key not in self.format_map: -+ msg = "ERROR *** XF[%d] unknown format key (%d, 0x%04x)\n" -+ fprintf(self.logfile, msg, -+ xf.xf_index, xf.format_key, xf.format_key) -+ xf.format_key = 0 -+ -+ fmt = self.format_map[xf.format_key] -+ cellty = _cellty_from_fmtty[fmt.type] -+ self._xf_index_to_xl_type_map[xf.xf_index] = cellty -+ # Now for some assertions etc -+ if not self.formatting_info: -+ continue -+ if xf.is_style: -+ continue -+ if not(0 <= xf.parent_style_index < num_xfs): -+ if blah1: -+ fprintf(self.logfile, -+ "WARNING *** XF[%d]: is_style=%d but parent_style_index=%d\n", -+ xf.xf_index, xf.is_style, xf.parent_style_index) -+ # make it conform -+ xf.parent_style_index = 0 -+ if self.biff_version >= 30: -+ if blah1: -+ if xf.parent_style_index == xf.xf_index: -+ fprintf(self.logfile, -+ "NOTE !!! XF[%d]: parent_style_index is also %d\n", -+ xf.xf_index, xf.parent_style_index) -+ elif not self.xf_list[xf.parent_style_index].is_style: -+ fprintf(self.logfile, -+ "NOTE !!! XF[%d]: parent_style_index is %d; style flag not set\n", -+ xf.xf_index, xf.parent_style_index) -+ if blah1 and xf.parent_style_index > xf.xf_index: -+ fprintf(self.logfile, -+ "NOTE !!! XF[%d]: parent_style_index is %d; out of order?\n", -+ xf.xf_index, xf.parent_style_index) -+ parent = self.xf_list[xf.parent_style_index] -+ if not xf._alignment_flag and not parent._alignment_flag: -+ if blah1: check_same(self, xf, parent, 'alignment') -+ if not xf._background_flag and not parent._background_flag: -+ if blah1: check_same(self, xf, parent, 'background') -+ if not xf._border_flag and not parent._border_flag: -+ if blah1: check_same(self, xf, parent, 'border') -+ if not xf._protection_flag and not parent._protection_flag: -+ if blah1: check_same(self, xf, parent, 'protection') -+ if not xf._format_flag and not parent._format_flag: -+ if blah1 and xf.format_key != parent.format_key: -+ fprintf(self.logfile, -+ "NOTE !!! XF[%d] fmtk=%d, parent[%d] fmtk=%r\n%r / %r\n", -+ xf.xf_index, xf.format_key, parent.xf_index, parent.format_key, -+ self.format_map[xf.format_key].format_str, -+ self.format_map[parent.format_key].format_str) -+ if not xf._font_flag and not parent._font_flag: -+ if blah1 and xf.font_index != parent.font_index: -+ fprintf(self.logfile, -+ "NOTE !!! XF[%d] fontx=%d, parent[%d] fontx=%r\n", -+ xf.xf_index, xf.font_index, parent.xf_index, parent.font_index) -+ -+def initialise_book(book): -+ initialise_colour_map(book) -+ book._xf_epilogue_done = 0 -+ methods = ( -+ handle_font, -+ handle_efont, -+ handle_format, -+ is_date_format_string, -+ handle_palette, -+ palette_epilogue, -+ handle_style, -+ handle_xf, -+ xf_epilogue, -+ ) -+ for method in methods: -+ setattr(book.__class__, method.__name__, method) -+ -+## -+#

A collection of the border-related attributes of an XF record. -+# Items correspond to those in the Excel UI's Format/Cells/Border tab.

-+#

An explanations of "colour index" is given in the Formatting -+# section at the start of this document. -+# There are five line style attributes; possible values and the -+# associated meanings are: -+# 0 = No line, -+# 1 = Thin, -+# 2 = Medium, -+# 3 = Dashed, -+# 4 = Dotted, -+# 5 = Thick, -+# 6 = Double, -+# 7 = Hair, -+# 8 = Medium dashed, -+# 9 = Thin dash-dotted, -+# 10 = Medium dash-dotted, -+# 11 = Thin dash-dot-dotted, -+# 12 = Medium dash-dot-dotted, -+# 13 = Slanted medium dash-dotted. -+# The line styles 8 to 13 appear in BIFF8 files (Excel 97 and later) only. -+# For pictures of the line styles, refer to OOo docs s3.10 (p22) -+# "Line Styles for Cell Borders (BIFF3-BIFF8)".

-+#
-- New in version 0.6.1 -+class XFBorder(BaseObject, EqNeAttrs): -+ -+ ## -+ # The colour index for the cell's top line -+ top_colour_index = 0 -+ ## -+ # The colour index for the cell's bottom line -+ bottom_colour_index = 0 -+ ## -+ # The colour index for the cell's left line -+ left_colour_index = 0 -+ ## -+ # The colour index for the cell's right line -+ right_colour_index = 0 -+ ## -+ # The colour index for the cell's diagonal lines, if any -+ diag_colour_index = 0 -+ ## -+ # The line style for the cell's top line -+ top_line_style = 0 -+ ## -+ # The line style for the cell's bottom line -+ bottom_line_style = 0 -+ ## -+ # The line style for the cell's left line -+ left_line_style = 0 -+ ## -+ # The line style for the cell's right line -+ right_line_style = 0 -+ ## -+ # The line style for the cell's diagonal lines, if any -+ diag_line_style = 0 -+ ## -+ # 1 = draw a diagonal from top left to bottom right -+ diag_down = 0 -+ ## -+ # 1 = draw a diagonal from bottom left to top right -+ diag_up = 0 -+ -+## -+# A collection of the background-related attributes of an XF record. -+# Items correspond to those in the Excel UI's Format/Cells/Patterns tab. -+# An explanation of "colour index" is given in the Formatting -+# section at the start of this document. -+#
-- New in version 0.6.1 -+class XFBackground(BaseObject, EqNeAttrs): -+ -+ ## -+ # See section 3.11 of the OOo docs. -+ fill_pattern = 0 -+ ## -+ # See section 3.11 of the OOo docs. -+ background_colour_index = 0 -+ ## -+ # See section 3.11 of the OOo docs. -+ pattern_colour_index = 0 -+ -+## -+# A collection of the alignment and similar attributes of an XF record. -+# Items correspond to those in the Excel UI's Format/Cells/Alignment tab. -+#
-- New in version 0.6.1 -+ -+class XFAlignment(BaseObject, EqNeAttrs): -+ -+ ## -+ # Values: section 6.115 (p 214) of OOo docs -+ hor_align = 0 -+ ## -+ # Values: section 6.115 (p 215) of OOo docs -+ vert_align = 0 -+ ## -+ # Values: section 6.115 (p 215) of OOo docs.
-+ # Note: file versions BIFF7 and earlier use the documented -+ # "orientation" attribute; this will be mapped (without loss) -+ # into "rotation". -+ rotation = 0 -+ ## -+ # 1 = text is wrapped at right margin -+ text_wrapped = 0 -+ ## -+ # A number in range(15). -+ indent_level = 0 -+ ## -+ # 1 = shrink font size to fit text into cell. -+ shrink_to_fit = 0 -+ ## -+ # 0 = according to context; 1 = left-to-right; 2 = right-to-left -+ text_direction = 0 -+ -+## -+# A collection of the protection-related attributes of an XF record. -+# Items correspond to those in the Excel UI's Format/Cells/Protection tab. -+# Note the OOo docs include the "cell or style" bit -+# in this bundle of attributes. -+# This is incorrect; the bit is used in determining which bundles to use. -+#
-- New in version 0.6.1 -+ -+class XFProtection(BaseObject, EqNeAttrs): -+ -+ ## -+ # 1 = Cell is prevented from being changed, moved, resized, or deleted -+ # (only if the sheet is protected). -+ cell_locked = 0 -+ ## -+ # 1 = Hide formula so that it doesn't appear in the formula bar when -+ # the cell is selected (only if the sheet is protected). -+ formula_hidden = 0 -+ -+## -+# eXtended Formatting information for cells, rows, columns and styles. -+#
-- New in version 0.6.1 -+# -+#

Each of the 6 flags below describes the validity of -+# a specific group of attributes. -+#
-+# In cell XFs, flag==0 means the attributes of the parent style XF are used, -+# (but only if the attributes are valid there); flag==1 means the attributes -+# of this XF are used.
-+# In style XFs, flag==0 means the attribute setting is valid; flag==1 means -+# the attribute should be ignored.
-+# Note that the API -+# provides both "raw" XFs and "computed" XFs -- in the latter case, cell XFs -+# have had the above inheritance mechanism applied. -+#

-+ -+class XF(BaseObject): -+ -+ ## -+ # 0 = cell XF, 1 = style XF -+ is_style = 0 -+ ## -+ # cell XF: Index into Book.xf_list -+ # of this XF's style XF
-+ # style XF: 0xFFF -+ parent_style_index = 0 -+ ## -+ # -+ _format_flag = 0 -+ ## -+ # -+ _font_flag = 0 -+ ## -+ # -+ _alignment_flag = 0 -+ ## -+ # -+ _border_flag = 0 -+ ## -+ # -+ _background_flag = 0 -+ ## -+ #   -+ _protection_flag = 0 -+ ## -+ # Index into Book.xf_list -+ xf_index = 0 -+ ## -+ # Index into Book.font_list -+ font_index = 0 -+ ## -+ # Key into Book.format_map -+ #

-+ # Warning: OOo docs on the XF record call this "Index to FORMAT record". -+ # It is not an index in the Python sense. It is a key to a map. -+ # It is true only for Excel 4.0 and earlier files -+ # that the key into format_map from an XF instance -+ # is the same as the index into format_list, and only -+ # if the index is less than 164. -+ #

-+ format_key = 0 -+ ## -+ # An instance of an XFProtection object. -+ protection = None -+ ## -+ # An instance of an XFBackground object. -+ background = None -+ ## -+ # An instance of an XFAlignment object. -+ alignment = None -+ ## -+ # An instance of an XFBorder object. -+ border = None -diff --git a/webhub/xlrd/formatting.pyc b/webhub/xlrd/formatting.pyc -new file mode 100644 -index 0000000..ec0e711 -Binary files /dev/null and b/webhub/xlrd/formatting.pyc differ -diff --git a/webhub/xlrd/formula.py b/webhub/xlrd/formula.py -new file mode 100644 -index 0000000..7c56aa4 ---- /dev/null -+++ b/webhub/xlrd/formula.py -@@ -0,0 +1,2179 @@ -+# -*- coding: cp1252 -*- -+ -+## -+# Module for parsing/evaluating Microsoft Excel formulas. -+# -+#

Copyright 2005-2012 Stephen John Machin, Lingfo Pty Ltd

-+#

This module is part of the xlrd package, which is released under -+# a BSD-style licence.

-+## -+ -+# No part of the content of this file was derived from the works of David Giffin. -+ -+from __future__ import print_function -+import copy -+from struct import unpack -+from .timemachine import * -+from .biffh import unpack_unicode_update_pos, unpack_string_update_pos, \ -+ XLRDError, hex_char_dump, error_text_from_code, BaseObject -+ -+__all__ = [ -+ 'oBOOL', 'oERR', 'oNUM', 'oREF', 'oREL', 'oSTRG', 'oUNK', -+ 'decompile_formula', -+ 'dump_formula', -+ 'evaluate_name_formula', -+ 'okind_dict', -+ 'rangename3d', 'rangename3drel', 'cellname', 'cellnameabs', 'colname', -+ 'FMLA_TYPE_CELL', -+ 'FMLA_TYPE_SHARED', -+ 'FMLA_TYPE_ARRAY', -+ 'FMLA_TYPE_COND_FMT', -+ 'FMLA_TYPE_DATA_VAL', -+ 'FMLA_TYPE_NAME', -+ ] -+ -+FMLA_TYPE_CELL = 1 -+FMLA_TYPE_SHARED = 2 -+FMLA_TYPE_ARRAY = 4 -+FMLA_TYPE_COND_FMT = 8 -+FMLA_TYPE_DATA_VAL = 16 -+FMLA_TYPE_NAME = 32 -+ALL_FMLA_TYPES = 63 -+ -+ -+FMLA_TYPEDESCR_MAP = { -+ 1 : 'CELL', -+ 2 : 'SHARED', -+ 4 : 'ARRAY', -+ 8 : 'COND-FMT', -+ 16: 'DATA-VAL', -+ 32: 'NAME', -+ } -+ -+_TOKEN_NOT_ALLOWED = { -+ 0x01: ALL_FMLA_TYPES - FMLA_TYPE_CELL, # tExp -+ 0x02: ALL_FMLA_TYPES - FMLA_TYPE_CELL, # tTbl -+ 0x0F: FMLA_TYPE_SHARED + FMLA_TYPE_COND_FMT + FMLA_TYPE_DATA_VAL, # tIsect -+ 0x10: FMLA_TYPE_SHARED + FMLA_TYPE_COND_FMT + FMLA_TYPE_DATA_VAL, # tUnion/List -+ 0x11: FMLA_TYPE_SHARED + FMLA_TYPE_COND_FMT + FMLA_TYPE_DATA_VAL, # tRange -+ 0x20: FMLA_TYPE_SHARED + FMLA_TYPE_COND_FMT + FMLA_TYPE_DATA_VAL, # tArray -+ 0x23: FMLA_TYPE_SHARED, # tName -+ 0x39: FMLA_TYPE_SHARED + FMLA_TYPE_COND_FMT + FMLA_TYPE_DATA_VAL, # tNameX -+ 0x3A: FMLA_TYPE_SHARED + FMLA_TYPE_COND_FMT + FMLA_TYPE_DATA_VAL, # tRef3d -+ 0x3B: FMLA_TYPE_SHARED + FMLA_TYPE_COND_FMT + FMLA_TYPE_DATA_VAL, # tArea3d -+ 0x2C: FMLA_TYPE_CELL + FMLA_TYPE_ARRAY, # tRefN -+ 0x2D: FMLA_TYPE_CELL + FMLA_TYPE_ARRAY, # tAreaN -+ # plus weird stuff like tMem* -+ }.get -+ -+oBOOL = 3 -+oERR = 4 -+oMSNG = 5 # tMissArg -+oNUM = 2 -+oREF = -1 -+oREL = -2 -+oSTRG = 1 -+oUNK = 0 -+ -+okind_dict = { -+ -2: "oREL", -+ -1: "oREF", -+ 0 : "oUNK", -+ 1 : "oSTRG", -+ 2 : "oNUM", -+ 3 : "oBOOL", -+ 4 : "oERR", -+ 5 : "oMSNG", -+ } -+ -+listsep = ',' #### probably should depend on locale -+ -+ -+# sztabN[opcode] -> the number of bytes to consume. -+# -1 means variable -+# -2 means this opcode not implemented in this version. -+# Which N to use? Depends on biff_version; see szdict. -+sztab0 = [-2, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -2, -1, 8, 4, 2, 2, 3, 9, 8, 2, 3, 8, 4, 7, 5, 5, 5, 2, 4, 7, 4, 7, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2, 3, -2, -2, -2, -2, -2, -2, -2] -+sztab1 = [-2, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -2, -1, 11, 5, 2, 2, 3, 9, 9, 2, 3, 11, 4, 7, 7, 7, 7, 3, 4, 7, 4, 7, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2, 3, -2, -2, -2, -2, -2, -2, -2] -+sztab2 = [-2, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -2, -1, 11, 5, 2, 2, 3, 9, 9, 3, 4, 11, 4, 7, 7, 7, 7, 3, 4, 7, 4, 7, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2] -+sztab3 = [-2, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -2, -1, -2, -2, 2, 2, 3, 9, 9, 3, 4, 15, 4, 7, 7, 7, 7, 3, 4, 7, 4, 7, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2, -2, 25, 18, 21, 18, 21, -2, -2] -+sztab4 = [-2, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -2, -2, 2, 2, 3, 9, 9, 3, 4, 5, 5, 9, 7, 7, 7, 3, 5, 9, 5, 9, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2, -2, 7, 7, 11, 7, 11, -2, -2] -+ -+szdict = { -+ 20 : sztab0, -+ 21 : sztab0, -+ 30 : sztab1, -+ 40 : sztab2, -+ 45 : sztab2, -+ 50 : sztab3, -+ 70 : sztab3, -+ 80 : sztab4, -+ } -+ -+# For debugging purposes ... the name for each opcode -+# (without the prefix "t" used on OOo docs) -+onames = ['Unk00', 'Exp', 'Tbl', 'Add', 'Sub', 'Mul', 'Div', 'Power', 'Concat', 'LT', 'LE', 'EQ', 'GE', 'GT', 'NE', 'Isect', 'List', 'Range', 'Uplus', 'Uminus', 'Percent', 'Paren', 'MissArg', 'Str', 'Extended', 'Attr', 'Sheet', 'EndSheet', 'Err', 'Bool', 'Int', 'Num', 'Array', 'Func', 'FuncVar', 'Name', 'Ref', 'Area', 'MemArea', 'MemErr', 'MemNoMem', 'MemFunc', 'RefErr', 'AreaErr', 'RefN', 'AreaN', 'MemAreaN', 'MemNoMemN', '', '', '', '', '', '', '', '', 'FuncCE', 'NameX', 'Ref3d', 'Area3d', 'RefErr3d', 'AreaErr3d', '', ''] -+ -+func_defs = { -+ # index: (name, min#args, max#args, flags, #known_args, return_type, kargs) -+ 0 : ('COUNT', 0, 30, 0x04, 1, 'V', 'R'), -+ 1 : ('IF', 2, 3, 0x04, 3, 'V', 'VRR'), -+ 2 : ('ISNA', 1, 1, 0x02, 1, 'V', 'V'), -+ 3 : ('ISERROR', 1, 1, 0x02, 1, 'V', 'V'), -+ 4 : ('SUM', 0, 30, 0x04, 1, 'V', 'R'), -+ 5 : ('AVERAGE', 1, 30, 0x04, 1, 'V', 'R'), -+ 6 : ('MIN', 1, 30, 0x04, 1, 'V', 'R'), -+ 7 : ('MAX', 1, 30, 0x04, 1, 'V', 'R'), -+ 8 : ('ROW', 0, 1, 0x04, 1, 'V', 'R'), -+ 9 : ('COLUMN', 0, 1, 0x04, 1, 'V', 'R'), -+ 10 : ('NA', 0, 0, 0x02, 0, 'V', ''), -+ 11 : ('NPV', 2, 30, 0x04, 2, 'V', 'VR'), -+ 12 : ('STDEV', 1, 30, 0x04, 1, 'V', 'R'), -+ 13 : ('DOLLAR', 1, 2, 0x04, 1, 'V', 'V'), -+ 14 : ('FIXED', 2, 3, 0x04, 3, 'V', 'VVV'), -+ 15 : ('SIN', 1, 1, 0x02, 1, 'V', 'V'), -+ 16 : ('COS', 1, 1, 0x02, 1, 'V', 'V'), -+ 17 : ('TAN', 1, 1, 0x02, 1, 'V', 'V'), -+ 18 : ('ATAN', 1, 1, 0x02, 1, 'V', 'V'), -+ 19 : ('PI', 0, 0, 0x02, 0, 'V', ''), -+ 20 : ('SQRT', 1, 1, 0x02, 1, 'V', 'V'), -+ 21 : ('EXP', 1, 1, 0x02, 1, 'V', 'V'), -+ 22 : ('LN', 1, 1, 0x02, 1, 'V', 'V'), -+ 23 : ('LOG10', 1, 1, 0x02, 1, 'V', 'V'), -+ 24 : ('ABS', 1, 1, 0x02, 1, 'V', 'V'), -+ 25 : ('INT', 1, 1, 0x02, 1, 'V', 'V'), -+ 26 : ('SIGN', 1, 1, 0x02, 1, 'V', 'V'), -+ 27 : ('ROUND', 2, 2, 0x02, 2, 'V', 'VV'), -+ 28 : ('LOOKUP', 2, 3, 0x04, 2, 'V', 'VR'), -+ 29 : ('INDEX', 2, 4, 0x0c, 4, 'R', 'RVVV'), -+ 30 : ('REPT', 2, 2, 0x02, 2, 'V', 'VV'), -+ 31 : ('MID', 3, 3, 0x02, 3, 'V', 'VVV'), -+ 32 : ('LEN', 1, 1, 0x02, 1, 'V', 'V'), -+ 33 : ('VALUE', 1, 1, 0x02, 1, 'V', 'V'), -+ 34 : ('TRUE', 0, 0, 0x02, 0, 'V', ''), -+ 35 : ('FALSE', 0, 0, 0x02, 0, 'V', ''), -+ 36 : ('AND', 1, 30, 0x04, 1, 'V', 'R'), -+ 37 : ('OR', 1, 30, 0x04, 1, 'V', 'R'), -+ 38 : ('NOT', 1, 1, 0x02, 1, 'V', 'V'), -+ 39 : ('MOD', 2, 2, 0x02, 2, 'V', 'VV'), -+ 40 : ('DCOUNT', 3, 3, 0x02, 3, 'V', 'RRR'), -+ 41 : ('DSUM', 3, 3, 0x02, 3, 'V', 'RRR'), -+ 42 : ('DAVERAGE', 3, 3, 0x02, 3, 'V', 'RRR'), -+ 43 : ('DMIN', 3, 3, 0x02, 3, 'V', 'RRR'), -+ 44 : ('DMAX', 3, 3, 0x02, 3, 'V', 'RRR'), -+ 45 : ('DSTDEV', 3, 3, 0x02, 3, 'V', 'RRR'), -+ 46 : ('VAR', 1, 30, 0x04, 1, 'V', 'R'), -+ 47 : ('DVAR', 3, 3, 0x02, 3, 'V', 'RRR'), -+ 48 : ('TEXT', 2, 2, 0x02, 2, 'V', 'VV'), -+ 49 : ('LINEST', 1, 4, 0x04, 4, 'A', 'RRVV'), -+ 50 : ('TREND', 1, 4, 0x04, 4, 'A', 'RRRV'), -+ 51 : ('LOGEST', 1, 4, 0x04, 4, 'A', 'RRVV'), -+ 52 : ('GROWTH', 1, 4, 0x04, 4, 'A', 'RRRV'), -+ 56 : ('PV', 3, 5, 0x04, 5, 'V', 'VVVVV'), -+ 57 : ('FV', 3, 5, 0x04, 5, 'V', 'VVVVV'), -+ 58 : ('NPER', 3, 5, 0x04, 5, 'V', 'VVVVV'), -+ 59 : ('PMT', 3, 5, 0x04, 5, 'V', 'VVVVV'), -+ 60 : ('RATE', 3, 6, 0x04, 6, 'V', 'VVVVVV'), -+ 61 : ('MIRR', 3, 3, 0x02, 3, 'V', 'RVV'), -+ 62 : ('IRR', 1, 2, 0x04, 2, 'V', 'RV'), -+ 63 : ('RAND', 0, 0, 0x0a, 0, 'V', ''), -+ 64 : ('MATCH', 2, 3, 0x04, 3, 'V', 'VRR'), -+ 65 : ('DATE', 3, 3, 0x02, 3, 'V', 'VVV'), -+ 66 : ('TIME', 3, 3, 0x02, 3, 'V', 'VVV'), -+ 67 : ('DAY', 1, 1, 0x02, 1, 'V', 'V'), -+ 68 : ('MONTH', 1, 1, 0x02, 1, 'V', 'V'), -+ 69 : ('YEAR', 1, 1, 0x02, 1, 'V', 'V'), -+ 70 : ('WEEKDAY', 1, 2, 0x04, 2, 'V', 'VV'), -+ 71 : ('HOUR', 1, 1, 0x02, 1, 'V', 'V'), -+ 72 : ('MINUTE', 1, 1, 0x02, 1, 'V', 'V'), -+ 73 : ('SECOND', 1, 1, 0x02, 1, 'V', 'V'), -+ 74 : ('NOW', 0, 0, 0x0a, 0, 'V', ''), -+ 75 : ('AREAS', 1, 1, 0x02, 1, 'V', 'R'), -+ 76 : ('ROWS', 1, 1, 0x02, 1, 'V', 'R'), -+ 77 : ('COLUMNS', 1, 1, 0x02, 1, 'V', 'R'), -+ 78 : ('OFFSET', 3, 5, 0x04, 5, 'R', 'RVVVV'), -+ 82 : ('SEARCH', 2, 3, 0x04, 3, 'V', 'VVV'), -+ 83 : ('TRANSPOSE', 1, 1, 0x02, 1, 'A', 'A'), -+ 86 : ('TYPE', 1, 1, 0x02, 1, 'V', 'V'), -+ 92 : ('SERIESSUM', 4, 4, 0x02, 4, 'V', 'VVVA'), -+ 97 : ('ATAN2', 2, 2, 0x02, 2, 'V', 'VV'), -+ 98 : ('ASIN', 1, 1, 0x02, 1, 'V', 'V'), -+ 99 : ('ACOS', 1, 1, 0x02, 1, 'V', 'V'), -+ 100: ('CHOOSE', 2, 30, 0x04, 2, 'V', 'VR'), -+ 101: ('HLOOKUP', 3, 4, 0x04, 4, 'V', 'VRRV'), -+ 102: ('VLOOKUP', 3, 4, 0x04, 4, 'V', 'VRRV'), -+ 105: ('ISREF', 1, 1, 0x02, 1, 'V', 'R'), -+ 109: ('LOG', 1, 2, 0x04, 2, 'V', 'VV'), -+ 111: ('CHAR', 1, 1, 0x02, 1, 'V', 'V'), -+ 112: ('LOWER', 1, 1, 0x02, 1, 'V', 'V'), -+ 113: ('UPPER', 1, 1, 0x02, 1, 'V', 'V'), -+ 114: ('PROPER', 1, 1, 0x02, 1, 'V', 'V'), -+ 115: ('LEFT', 1, 2, 0x04, 2, 'V', 'VV'), -+ 116: ('RIGHT', 1, 2, 0x04, 2, 'V', 'VV'), -+ 117: ('EXACT', 2, 2, 0x02, 2, 'V', 'VV'), -+ 118: ('TRIM', 1, 1, 0x02, 1, 'V', 'V'), -+ 119: ('REPLACE', 4, 4, 0x02, 4, 'V', 'VVVV'), -+ 120: ('SUBSTITUTE', 3, 4, 0x04, 4, 'V', 'VVVV'), -+ 121: ('CODE', 1, 1, 0x02, 1, 'V', 'V'), -+ 124: ('FIND', 2, 3, 0x04, 3, 'V', 'VVV'), -+ 125: ('CELL', 1, 2, 0x0c, 2, 'V', 'VR'), -+ 126: ('ISERR', 1, 1, 0x02, 1, 'V', 'V'), -+ 127: ('ISTEXT', 1, 1, 0x02, 1, 'V', 'V'), -+ 128: ('ISNUMBER', 1, 1, 0x02, 1, 'V', 'V'), -+ 129: ('ISBLANK', 1, 1, 0x02, 1, 'V', 'V'), -+ 130: ('T', 1, 1, 0x02, 1, 'V', 'R'), -+ 131: ('N', 1, 1, 0x02, 1, 'V', 'R'), -+ 140: ('DATEVALUE', 1, 1, 0x02, 1, 'V', 'V'), -+ 141: ('TIMEVALUE', 1, 1, 0x02, 1, 'V', 'V'), -+ 142: ('SLN', 3, 3, 0x02, 3, 'V', 'VVV'), -+ 143: ('SYD', 4, 4, 0x02, 4, 'V', 'VVVV'), -+ 144: ('DDB', 4, 5, 0x04, 5, 'V', 'VVVVV'), -+ 148: ('INDIRECT', 1, 2, 0x0c, 2, 'R', 'VV'), -+ 162: ('CLEAN', 1, 1, 0x02, 1, 'V', 'V'), -+ 163: ('MDETERM', 1, 1, 0x02, 1, 'V', 'A'), -+ 164: ('MINVERSE', 1, 1, 0x02, 1, 'A', 'A'), -+ 165: ('MMULT', 2, 2, 0x02, 2, 'A', 'AA'), -+ 167: ('IPMT', 4, 6, 0x04, 6, 'V', 'VVVVVV'), -+ 168: ('PPMT', 4, 6, 0x04, 6, 'V', 'VVVVVV'), -+ 169: ('COUNTA', 0, 30, 0x04, 1, 'V', 'R'), -+ 183: ('PRODUCT', 0, 30, 0x04, 1, 'V', 'R'), -+ 184: ('FACT', 1, 1, 0x02, 1, 'V', 'V'), -+ 189: ('DPRODUCT', 3, 3, 0x02, 3, 'V', 'RRR'), -+ 190: ('ISNONTEXT', 1, 1, 0x02, 1, 'V', 'V'), -+ 193: ('STDEVP', 1, 30, 0x04, 1, 'V', 'R'), -+ 194: ('VARP', 1, 30, 0x04, 1, 'V', 'R'), -+ 195: ('DSTDEVP', 3, 3, 0x02, 3, 'V', 'RRR'), -+ 196: ('DVARP', 3, 3, 0x02, 3, 'V', 'RRR'), -+ 197: ('TRUNC', 1, 2, 0x04, 2, 'V', 'VV'), -+ 198: ('ISLOGICAL', 1, 1, 0x02, 1, 'V', 'V'), -+ 199: ('DCOUNTA', 3, 3, 0x02, 3, 'V', 'RRR'), -+ 204: ('USDOLLAR', 1, 2, 0x04, 2, 'V', 'VV'), -+ 205: ('FINDB', 2, 3, 0x04, 3, 'V', 'VVV'), -+ 206: ('SEARCHB', 2, 3, 0x04, 3, 'V', 'VVV'), -+ 207: ('REPLACEB', 4, 4, 0x02, 4, 'V', 'VVVV'), -+ 208: ('LEFTB', 1, 2, 0x04, 2, 'V', 'VV'), -+ 209: ('RIGHTB', 1, 2, 0x04, 2, 'V', 'VV'), -+ 210: ('MIDB', 3, 3, 0x02, 3, 'V', 'VVV'), -+ 211: ('LENB', 1, 1, 0x02, 1, 'V', 'V'), -+ 212: ('ROUNDUP', 2, 2, 0x02, 2, 'V', 'VV'), -+ 213: ('ROUNDDOWN', 2, 2, 0x02, 2, 'V', 'VV'), -+ 214: ('ASC', 1, 1, 0x02, 1, 'V', 'V'), -+ 215: ('DBCS', 1, 1, 0x02, 1, 'V', 'V'), -+ 216: ('RANK', 2, 3, 0x04, 3, 'V', 'VRV'), -+ 219: ('ADDRESS', 2, 5, 0x04, 5, 'V', 'VVVVV'), -+ 220: ('DAYS360', 2, 3, 0x04, 3, 'V', 'VVV'), -+ 221: ('TODAY', 0, 0, 0x0a, 0, 'V', ''), -+ 222: ('VDB', 5, 7, 0x04, 7, 'V', 'VVVVVVV'), -+ 227: ('MEDIAN', 1, 30, 0x04, 1, 'V', 'R'), -+ 228: ('SUMPRODUCT', 1, 30, 0x04, 1, 'V', 'A'), -+ 229: ('SINH', 1, 1, 0x02, 1, 'V', 'V'), -+ 230: ('COSH', 1, 1, 0x02, 1, 'V', 'V'), -+ 231: ('TANH', 1, 1, 0x02, 1, 'V', 'V'), -+ 232: ('ASINH', 1, 1, 0x02, 1, 'V', 'V'), -+ 233: ('ACOSH', 1, 1, 0x02, 1, 'V', 'V'), -+ 234: ('ATANH', 1, 1, 0x02, 1, 'V', 'V'), -+ 235: ('DGET', 3, 3, 0x02, 3, 'V', 'RRR'), -+ 244: ('INFO', 1, 1, 0x02, 1, 'V', 'V'), -+ 247: ('DB', 4, 5, 0x04, 5, 'V', 'VVVVV'), -+ 252: ('FREQUENCY', 2, 2, 0x02, 2, 'A', 'RR'), -+ 261: ('ERROR.TYPE', 1, 1, 0x02, 1, 'V', 'V'), -+ 269: ('AVEDEV', 1, 30, 0x04, 1, 'V', 'R'), -+ 270: ('BETADIST', 3, 5, 0x04, 1, 'V', 'V'), -+ 271: ('GAMMALN', 1, 1, 0x02, 1, 'V', 'V'), -+ 272: ('BETAINV', 3, 5, 0x04, 1, 'V', 'V'), -+ 273: ('BINOMDIST', 4, 4, 0x02, 4, 'V', 'VVVV'), -+ 274: ('CHIDIST', 2, 2, 0x02, 2, 'V', 'VV'), -+ 275: ('CHIINV', 2, 2, 0x02, 2, 'V', 'VV'), -+ 276: ('COMBIN', 2, 2, 0x02, 2, 'V', 'VV'), -+ 277: ('CONFIDENCE', 3, 3, 0x02, 3, 'V', 'VVV'), -+ 278: ('CRITBINOM', 3, 3, 0x02, 3, 'V', 'VVV'), -+ 279: ('EVEN', 1, 1, 0x02, 1, 'V', 'V'), -+ 280: ('EXPONDIST', 3, 3, 0x02, 3, 'V', 'VVV'), -+ 281: ('FDIST', 3, 3, 0x02, 3, 'V', 'VVV'), -+ 282: ('FINV', 3, 3, 0x02, 3, 'V', 'VVV'), -+ 283: ('FISHER', 1, 1, 0x02, 1, 'V', 'V'), -+ 284: ('FISHERINV', 1, 1, 0x02, 1, 'V', 'V'), -+ 285: ('FLOOR', 2, 2, 0x02, 2, 'V', 'VV'), -+ 286: ('GAMMADIST', 4, 4, 0x02, 4, 'V', 'VVVV'), -+ 287: ('GAMMAINV', 3, 3, 0x02, 3, 'V', 'VVV'), -+ 288: ('CEILING', 2, 2, 0x02, 2, 'V', 'VV'), -+ 289: ('HYPGEOMDIST', 4, 4, 0x02, 4, 'V', 'VVVV'), -+ 290: ('LOGNORMDIST', 3, 3, 0x02, 3, 'V', 'VVV'), -+ 291: ('LOGINV', 3, 3, 0x02, 3, 'V', 'VVV'), -+ 292: ('NEGBINOMDIST', 3, 3, 0x02, 3, 'V', 'VVV'), -+ 293: ('NORMDIST', 4, 4, 0x02, 4, 'V', 'VVVV'), -+ 294: ('NORMSDIST', 1, 1, 0x02, 1, 'V', 'V'), -+ 295: ('NORMINV', 3, 3, 0x02, 3, 'V', 'VVV'), -+ 296: ('NORMSINV', 1, 1, 0x02, 1, 'V', 'V'), -+ 297: ('STANDARDIZE', 3, 3, 0x02, 3, 'V', 'VVV'), -+ 298: ('ODD', 1, 1, 0x02, 1, 'V', 'V'), -+ 299: ('PERMUT', 2, 2, 0x02, 2, 'V', 'VV'), -+ 300: ('POISSON', 3, 3, 0x02, 3, 'V', 'VVV'), -+ 301: ('TDIST', 3, 3, 0x02, 3, 'V', 'VVV'), -+ 302: ('WEIBULL', 4, 4, 0x02, 4, 'V', 'VVVV'), -+ 303: ('SUMXMY2', 2, 2, 0x02, 2, 'V', 'AA'), -+ 304: ('SUMX2MY2', 2, 2, 0x02, 2, 'V', 'AA'), -+ 305: ('SUMX2PY2', 2, 2, 0x02, 2, 'V', 'AA'), -+ 306: ('CHITEST', 2, 2, 0x02, 2, 'V', 'AA'), -+ 307: ('CORREL', 2, 2, 0x02, 2, 'V', 'AA'), -+ 308: ('COVAR', 2, 2, 0x02, 2, 'V', 'AA'), -+ 309: ('FORECAST', 3, 3, 0x02, 3, 'V', 'VAA'), -+ 310: ('FTEST', 2, 2, 0x02, 2, 'V', 'AA'), -+ 311: ('INTERCEPT', 2, 2, 0x02, 2, 'V', 'AA'), -+ 312: ('PEARSON', 2, 2, 0x02, 2, 'V', 'AA'), -+ 313: ('RSQ', 2, 2, 0x02, 2, 'V', 'AA'), -+ 314: ('STEYX', 2, 2, 0x02, 2, 'V', 'AA'), -+ 315: ('SLOPE', 2, 2, 0x02, 2, 'V', 'AA'), -+ 316: ('TTEST', 4, 4, 0x02, 4, 'V', 'AAVV'), -+ 317: ('PROB', 3, 4, 0x04, 3, 'V', 'AAV'), -+ 318: ('DEVSQ', 1, 30, 0x04, 1, 'V', 'R'), -+ 319: ('GEOMEAN', 1, 30, 0x04, 1, 'V', 'R'), -+ 320: ('HARMEAN', 1, 30, 0x04, 1, 'V', 'R'), -+ 321: ('SUMSQ', 0, 30, 0x04, 1, 'V', 'R'), -+ 322: ('KURT', 1, 30, 0x04, 1, 'V', 'R'), -+ 323: ('SKEW', 1, 30, 0x04, 1, 'V', 'R'), -+ 324: ('ZTEST', 2, 3, 0x04, 2, 'V', 'RV'), -+ 325: ('LARGE', 2, 2, 0x02, 2, 'V', 'RV'), -+ 326: ('SMALL', 2, 2, 0x02, 2, 'V', 'RV'), -+ 327: ('QUARTILE', 2, 2, 0x02, 2, 'V', 'RV'), -+ 328: ('PERCENTILE', 2, 2, 0x02, 2, 'V', 'RV'), -+ 329: ('PERCENTRANK', 2, 3, 0x04, 2, 'V', 'RV'), -+ 330: ('MODE', 1, 30, 0x04, 1, 'V', 'A'), -+ 331: ('TRIMMEAN', 2, 2, 0x02, 2, 'V', 'RV'), -+ 332: ('TINV', 2, 2, 0x02, 2, 'V', 'VV'), -+ 336: ('CONCATENATE', 0, 30, 0x04, 1, 'V', 'V'), -+ 337: ('POWER', 2, 2, 0x02, 2, 'V', 'VV'), -+ 342: ('RADIANS', 1, 1, 0x02, 1, 'V', 'V'), -+ 343: ('DEGREES', 1, 1, 0x02, 1, 'V', 'V'), -+ 344: ('SUBTOTAL', 2, 30, 0x04, 2, 'V', 'VR'), -+ 345: ('SUMIF', 2, 3, 0x04, 3, 'V', 'RVR'), -+ 346: ('COUNTIF', 2, 2, 0x02, 2, 'V', 'RV'), -+ 347: ('COUNTBLANK', 1, 1, 0x02, 1, 'V', 'R'), -+ 350: ('ISPMT', 4, 4, 0x02, 4, 'V', 'VVVV'), -+ 351: ('DATEDIF', 3, 3, 0x02, 3, 'V', 'VVV'), -+ 352: ('DATESTRING', 1, 1, 0x02, 1, 'V', 'V'), -+ 353: ('NUMBERSTRING', 2, 2, 0x02, 2, 'V', 'VV'), -+ 354: ('ROMAN', 1, 2, 0x04, 2, 'V', 'VV'), -+ 358: ('GETPIVOTDATA', 2, 2, 0x02, 2, 'V', 'RV'), -+ 359: ('HYPERLINK', 1, 2, 0x04, 2, 'V', 'VV'), -+ 360: ('PHONETIC', 1, 1, 0x02, 1, 'V', 'V'), -+ 361: ('AVERAGEA', 1, 30, 0x04, 1, 'V', 'R'), -+ 362: ('MAXA', 1, 30, 0x04, 1, 'V', 'R'), -+ 363: ('MINA', 1, 30, 0x04, 1, 'V', 'R'), -+ 364: ('STDEVPA', 1, 30, 0x04, 1, 'V', 'R'), -+ 365: ('VARPA', 1, 30, 0x04, 1, 'V', 'R'), -+ 366: ('STDEVA', 1, 30, 0x04, 1, 'V', 'R'), -+ 367: ('VARA', 1, 30, 0x04, 1, 'V', 'R'), -+ 368: ('BAHTTEXT', 1, 1, 0x02, 1, 'V', 'V'), -+ 369: ('THAIDAYOFWEEK', 1, 1, 0x02, 1, 'V', 'V'), -+ 370: ('THAIDIGIT', 1, 1, 0x02, 1, 'V', 'V'), -+ 371: ('THAIMONTHOFYEAR', 1, 1, 0x02, 1, 'V', 'V'), -+ 372: ('THAINUMSOUND', 1, 1, 0x02, 1, 'V', 'V'), -+ 373: ('THAINUMSTRING', 1, 1, 0x02, 1, 'V', 'V'), -+ 374: ('THAISTRINGLENGTH', 1, 1, 0x02, 1, 'V', 'V'), -+ 375: ('ISTHAIDIGIT', 1, 1, 0x02, 1, 'V', 'V'), -+ 376: ('ROUNDBAHTDOWN', 1, 1, 0x02, 1, 'V', 'V'), -+ 377: ('ROUNDBAHTUP', 1, 1, 0x02, 1, 'V', 'V'), -+ 378: ('THAIYEAR', 1, 1, 0x02, 1, 'V', 'V'), -+ 379: ('RTD', 2, 5, 0x04, 1, 'V', 'V'), -+ } -+ -+tAttrNames = { -+ 0x00: "Skip??", # seen in SAMPLES.XLS which shipped with Excel 5.0 -+ 0x01: "Volatile", -+ 0x02: "If", -+ 0x04: "Choose", -+ 0x08: "Skip", -+ 0x10: "Sum", -+ 0x20: "Assign", -+ 0x40: "Space", -+ 0x41: "SpaceVolatile", -+ } -+ -+error_opcodes = set([0x07, 0x08, 0x0A, 0x0B, 0x1C, 0x1D, 0x2F]) -+ -+tRangeFuncs = (min, max, min, max, min, max) -+tIsectFuncs = (max, min, max, min, max, min) -+ -+def do_box_funcs(box_funcs, boxa, boxb): -+ return tuple([ -+ func(numa, numb) -+ for func, numa, numb in zip(box_funcs, boxa.coords, boxb.coords) -+ ]) -+ -+def adjust_cell_addr_biff8(rowval, colval, reldelta, browx=None, bcolx=None): -+ row_rel = (colval >> 15) & 1 -+ col_rel = (colval >> 14) & 1 -+ rowx = rowval -+ colx = colval & 0xff -+ if reldelta: -+ if row_rel and rowx >= 32768: -+ rowx -= 65536 -+ if col_rel and colx >= 128: -+ colx -= 256 -+ else: -+ if row_rel: -+ rowx -= browx -+ if col_rel: -+ colx -= bcolx -+ return rowx, colx, row_rel, col_rel -+ -+def adjust_cell_addr_biff_le7( -+ rowval, colval, reldelta, browx=None, bcolx=None): -+ row_rel = (rowval >> 15) & 1 -+ col_rel = (rowval >> 14) & 1 -+ rowx = rowval & 0x3fff -+ colx = colval -+ if reldelta: -+ if row_rel and rowx >= 8192: -+ rowx -= 16384 -+ if col_rel and colx >= 128: -+ colx -= 256 -+ else: -+ if row_rel: -+ rowx -= browx -+ if col_rel: -+ colx -= bcolx -+ return rowx, colx, row_rel, col_rel -+ -+def get_cell_addr(data, pos, bv, reldelta, browx=None, bcolx=None): -+ if bv >= 80: -+ rowval, colval = unpack("= 80: -+ row1val, row2val, col1val, col2val = unpack(" addins %r" % (refx, info), file=bk.logfile) -+ assert ref_first_sheetx == 0xFFFE == ref_last_sheetx -+ return (-5, -5) -+ if ref_recordx != bk._supbook_locals_inx: -+ if blah: -+ print("/// get_externsheet_local_range(refx=%d) -> external %r" % (refx, info), file=bk.logfile) -+ return (-4, -4) # external reference -+ if ref_first_sheetx == 0xFFFE == ref_last_sheetx: -+ if blah: -+ print("/// get_externsheet_local_range(refx=%d) -> unspecified sheet %r" % (refx, info), file=bk.logfile) -+ return (-1, -1) # internal reference, any sheet -+ if ref_first_sheetx == 0xFFFF == ref_last_sheetx: -+ if blah: -+ print("/// get_externsheet_local_range(refx=%d) -> deleted sheet(s)" % (refx, ), file=bk.logfile) -+ return (-2, -2) # internal reference, deleted sheet(s) -+ nsheets = len(bk._all_sheets_map) -+ if not(0 <= ref_first_sheetx <= ref_last_sheetx < nsheets): -+ if blah: -+ print("/// get_externsheet_local_range(refx=%d) -> %r" % (refx, info), file=bk.logfile) -+ print("--- first/last sheet not in range(%d)" % nsheets, file=bk.logfile) -+ return (-102, -102) # stuffed up somewhere :-( -+ xlrd_sheetx1 = bk._all_sheets_map[ref_first_sheetx] -+ xlrd_sheetx2 = bk._all_sheets_map[ref_last_sheetx] -+ if not(0 <= xlrd_sheetx1 <= xlrd_sheetx2): -+ return (-3, -3) # internal reference, but to a macro sheet -+ return xlrd_sheetx1, xlrd_sheetx2 -+ -+def get_externsheet_local_range_b57( -+ bk, raw_extshtx, ref_first_sheetx, ref_last_sheetx, blah=0): -+ if raw_extshtx > 0: -+ if blah: -+ print("/// get_externsheet_local_range_b57(raw_extshtx=%d) -> external" % raw_extshtx, file=bk.logfile) -+ return (-4, -4) # external reference -+ if ref_first_sheetx == -1 and ref_last_sheetx == -1: -+ return (-2, -2) # internal reference, deleted sheet(s) -+ nsheets = len(bk._all_sheets_map) -+ if not(0 <= ref_first_sheetx <= ref_last_sheetx < nsheets): -+ if blah: -+ print("/// get_externsheet_local_range_b57(%d, %d, %d) -> ???" \ -+ % (raw_extshtx, ref_first_sheetx, ref_last_sheetx), file=bk.logfile) -+ print("--- first/last sheet not in range(%d)" % nsheets, file=bk.logfile) -+ return (-103, -103) # stuffed up somewhere :-( -+ xlrd_sheetx1 = bk._all_sheets_map[ref_first_sheetx] -+ xlrd_sheetx2 = bk._all_sheets_map[ref_last_sheetx] -+ if not(0 <= xlrd_sheetx1 <= xlrd_sheetx2): -+ return (-3, -3) # internal reference, but to a macro sheet -+ return xlrd_sheetx1, xlrd_sheetx2 -+ -+class FormulaError(Exception): -+ pass -+ -+ -+## -+# Used in evaluating formulas. -+# The following table describes the kinds and how their values -+# are represented.

-+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+#
Kind symbolKind numberValue representation
oBOOL3integer: 0 => False; 1 => True
oERR4None, or an int error code (same as XL_CELL_ERROR in the Cell class). -+#
oMSNG5Used by Excel as a placeholder for a missing (not supplied) function -+# argument. Should *not* appear as a final formula result. Value is None.
oNUM2A float. Note that there is no way of distinguishing dates.
oREF-1The value is either None or a non-empty list of -+# absolute Ref3D instances.
-+#
oREL-2The value is None or a non-empty list of -+# fully or partially relative Ref3D instances. -+#
oSTRG1A Unicode string.
oUNK0The kind is unknown or ambiguous. The value is None
-+#

-+ -+class Operand(object): -+ -+ ## -+ # None means that the actual value of the operand is a variable -+ # (depends on cell data), not a constant. -+ value = None -+ ## -+ # oUNK means that the kind of operand is not known unambiguously. -+ kind = oUNK -+ ## -+ # The reconstituted text of the original formula. Function names will be -+ # in English irrespective of the original language, which doesn't seem -+ # to be recorded anywhere. The separator is ",", not ";" or whatever else -+ # might be more appropriate for the end-user's locale; patches welcome. -+ text = '?' -+ -+ def __init__(self, akind=None, avalue=None, arank=0, atext='?'): -+ if akind is not None: -+ self.kind = akind -+ if avalue is not None: -+ self.value = avalue -+ self.rank = arank -+ # rank is an internal gizmo (operator precedence); -+ # it's used in reconstructing formula text. -+ self.text = atext -+ -+ def __repr__(self): -+ kind_text = okind_dict.get(self.kind, "?Unknown kind?") -+ return "Operand(kind=%s, value=%r, text=%r)" \ -+ % (kind_text, self.value, self.text) -+ -+## -+#

Represents an absolute or relative 3-dimensional reference to a box -+# of one or more cells.
-+# -- New in version 0.6.0 -+#

-+# -+#

The coords attribute is a tuple of the form:
-+# (shtxlo, shtxhi, rowxlo, rowxhi, colxlo, colxhi)
-+# where 0 <= thingxlo <= thingx < thingxhi.
-+# Note that it is quite possible to have thingx > nthings; for example -+# Print_Titles could have colxhi == 256 and/or rowxhi == 65536 -+# irrespective of how many columns/rows are actually used in the worksheet. -+# The caller will need to decide how to handle this situation. -+# Keyword: IndexError :-) -+#

-+# -+#

The components of the coords attribute are also available as individual -+# attributes: shtxlo, shtxhi, rowxlo, rowxhi, colxlo, and colxhi.

-+# -+#

The relflags attribute is a 6-tuple of flags which indicate whether -+# the corresponding (sheet|row|col)(lo|hi) is relative (1) or absolute (0).
-+# Note that there is necessarily no information available as to what cell(s) -+# the reference could possibly be relative to. The caller must decide what if -+# any use to make of oREL operands. Note also that a partially relative -+# reference may well be a typo. -+# For example, define name A1Z10 as $a$1:$z10 (missing $ after z) -+# while the cursor is on cell Sheet3!A27.
-+# The resulting Ref3D instance will have coords = (2, 3, 0, -16, 0, 26) -+# and relflags = (0, 0, 0, 1, 0, 0).
-+# So far, only one possibility of a sheet-relative component in -+# a reference has been noticed: a 2D reference located in the "current sheet". -+#
This will appear as coords = (0, 1, ...) and relflags = (1, 1, ...). -+ -+class Ref3D(tuple): -+ -+ def __init__(self, atuple): -+ self.coords = atuple[0:6] -+ self.relflags = atuple[6:12] -+ if not self.relflags: -+ self.relflags = (0, 0, 0, 0, 0, 0) -+ (self.shtxlo, self.shtxhi, -+ self.rowxlo, self.rowxhi, -+ self.colxlo, self.colxhi) = self.coords -+ -+ def __repr__(self): -+ if not self.relflags or self.relflags == (0, 0, 0, 0, 0, 0): -+ return "Ref3D(coords=%r)" % (self.coords, ) -+ else: -+ return "Ref3D(coords=%r, relflags=%r)" \ -+ % (self.coords, self.relflags) -+ -+tAdd = 0x03 -+tSub = 0x04 -+tMul = 0x05 -+tDiv = 0x06 -+tPower = 0x07 -+tConcat = 0x08 -+tLT, tLE, tEQ, tGE, tGT, tNE = range(0x09, 0x0F) -+ -+import operator as opr -+ -+def nop(x): -+ return x -+ -+def _opr_pow(x, y): return x ** y -+ -+def _opr_lt(x, y): return x < y -+def _opr_le(x, y): return x <= y -+def _opr_eq(x, y): return x == y -+def _opr_ge(x, y): return x >= y -+def _opr_gt(x, y): return x > y -+def _opr_ne(x, y): return x != y -+ -+def num2strg(num): -+ """Attempt to emulate Excel's default conversion -+ from number to string. -+ """ -+ s = str(num) -+ if s.endswith(".0"): -+ s = s[:-2] -+ return s -+ -+_arith_argdict = {oNUM: nop, oSTRG: float} -+_cmp_argdict = {oNUM: nop, oSTRG: nop} -+# Seems no conversions done on relops; in Excel, "1" > 9 produces TRUE. -+_strg_argdict = {oNUM:num2strg, oSTRG:nop} -+binop_rules = { -+ tAdd: (_arith_argdict, oNUM, opr.add, 30, '+'), -+ tSub: (_arith_argdict, oNUM, opr.sub, 30, '-'), -+ tMul: (_arith_argdict, oNUM, opr.mul, 40, '*'), -+ tDiv: (_arith_argdict, oNUM, opr.truediv, 40, '/'), -+ tPower: (_arith_argdict, oNUM, _opr_pow, 50, '^',), -+ tConcat:(_strg_argdict, oSTRG, opr.add, 20, '&'), -+ tLT: (_cmp_argdict, oBOOL, _opr_lt, 10, '<'), -+ tLE: (_cmp_argdict, oBOOL, _opr_le, 10, '<='), -+ tEQ: (_cmp_argdict, oBOOL, _opr_eq, 10, '='), -+ tGE: (_cmp_argdict, oBOOL, _opr_ge, 10, '>='), -+ tGT: (_cmp_argdict, oBOOL, _opr_gt, 10, '>'), -+ tNE: (_cmp_argdict, oBOOL, _opr_ne, 10, '<>'), -+ } -+ -+unop_rules = { -+ 0x13: (lambda x: -x, 70, '-', ''), # unary minus -+ 0x12: (lambda x: x, 70, '+', ''), # unary plus -+ 0x14: (lambda x: x / 100.0, 60, '', '%'),# percent -+ } -+ -+LEAF_RANK = 90 -+FUNC_RANK = 90 -+ -+STACK_ALARM_LEVEL = 5 -+STACK_PANIC_LEVEL = 10 -+ -+def evaluate_name_formula(bk, nobj, namex, blah=0, level=0): -+ if level > STACK_ALARM_LEVEL: -+ blah = 1 -+ data = nobj.raw_formula -+ fmlalen = nobj.basic_formula_len -+ bv = bk.biff_version -+ reldelta = 1 # All defined name formulas use "Method B" [OOo docs] -+ if blah: -+ print("::: evaluate_name_formula %r %r %d %d %r level=%d" \ -+ % (namex, nobj.name, fmlalen, bv, data, level), file=bk.logfile) -+ hex_char_dump(data, 0, fmlalen, fout=bk.logfile) -+ if level > STACK_PANIC_LEVEL: -+ raise XLRDError("Excessive indirect references in NAME formula") -+ sztab = szdict[bv] -+ pos = 0 -+ stack = [] -+ any_rel = 0 -+ any_err = 0 -+ any_external = 0 -+ unk_opnd = Operand(oUNK, None) -+ error_opnd = Operand(oERR, None) -+ spush = stack.append -+ -+ def do_binop(opcd, stk): -+ assert len(stk) >= 2 -+ bop = stk.pop() -+ aop = stk.pop() -+ argdict, result_kind, func, rank, sym = binop_rules[opcd] -+ otext = ''.join([ -+ '('[:aop.rank < rank], -+ aop.text, -+ ')'[:aop.rank < rank], -+ sym, -+ '('[:bop.rank < rank], -+ bop.text, -+ ')'[:bop.rank < rank], -+ ]) -+ resop = Operand(result_kind, None, rank, otext) -+ try: -+ bconv = argdict[bop.kind] -+ aconv = argdict[aop.kind] -+ except KeyError: -+ stk.append(resop) -+ return -+ if bop.value is None or aop.value is None: -+ stk.append(resop) -+ return -+ bval = bconv(bop.value) -+ aval = aconv(aop.value) -+ result = func(aval, bval) -+ if result_kind == oBOOL: -+ result = 1 if result else 0 -+ resop.value = result -+ stk.append(resop) -+ -+ def do_unaryop(opcode, result_kind, stk): -+ assert len(stk) >= 1 -+ aop = stk.pop() -+ val = aop.value -+ func, rank, sym1, sym2 = unop_rules[opcode] -+ otext = ''.join([ -+ sym1, -+ '('[:aop.rank < rank], -+ aop.text, -+ ')'[:aop.rank < rank], -+ sym2, -+ ]) -+ if val is not None: -+ val = func(val) -+ stk.append(Operand(result_kind, val, rank, otext)) -+ -+ def not_in_name_formula(op_arg, oname_arg): -+ msg = "ERROR *** Token 0x%02x (%s) found in NAME formula" \ -+ % (op_arg, oname_arg) -+ raise FormulaError(msg) -+ -+ if fmlalen == 0: -+ stack = [unk_opnd] -+ -+ while 0 <= pos < fmlalen: -+ op = BYTES_ORD(data[pos]) -+ opcode = op & 0x1f -+ optype = (op & 0x60) >> 5 -+ if optype: -+ opx = opcode + 32 -+ else: -+ opx = opcode -+ oname = onames[opx] # + [" RVA"][optype] -+ sz = sztab[opx] -+ if blah: -+ print("Pos:%d Op:0x%02x Name:t%s Sz:%d opcode:%02xh optype:%02xh" \ -+ % (pos, op, oname, sz, opcode, optype), file=bk.logfile) -+ print("Stack =", stack, file=bk.logfile) -+ if sz == -2: -+ msg = 'ERROR *** Unexpected token 0x%02x ("%s"); biff_version=%d' \ -+ % (op, oname, bv) -+ raise FormulaError(msg) -+ if not optype: -+ if 0x00 <= opcode <= 0x02: # unk_opnd, tExp, tTbl -+ not_in_name_formula(op, oname) -+ elif 0x03 <= opcode <= 0x0E: -+ # Add, Sub, Mul, Div, Power -+ # tConcat -+ # tLT, ..., tNE -+ do_binop(opcode, stack) -+ elif opcode == 0x0F: # tIsect -+ if blah: print("tIsect pre", stack, file=bk.logfile) -+ assert len(stack) >= 2 -+ bop = stack.pop() -+ aop = stack.pop() -+ sym = ' ' -+ rank = 80 ########## check ####### -+ otext = ''.join([ -+ '('[:aop.rank < rank], -+ aop.text, -+ ')'[:aop.rank < rank], -+ sym, -+ '('[:bop.rank < rank], -+ bop.text, -+ ')'[:bop.rank < rank], -+ ]) -+ res = Operand(oREF) -+ res.text = otext -+ if bop.kind == oERR or aop.kind == oERR: -+ res.kind = oERR -+ elif bop.kind == oUNK or aop.kind == oUNK: -+ # This can happen with undefined -+ # (go search in the current sheet) labels. -+ # For example =Bob Sales -+ # Each label gets a NAME record with an empty formula (!) -+ # Evaluation of the tName token classifies it as oUNK -+ # res.kind = oREF -+ pass -+ elif bop.kind == oREF == aop.kind: -+ if aop.value is not None and bop.value is not None: -+ assert len(aop.value) == 1 -+ assert len(bop.value) == 1 -+ coords = do_box_funcs( -+ tIsectFuncs, aop.value[0], bop.value[0]) -+ res.value = [Ref3D(coords)] -+ elif bop.kind == oREL == aop.kind: -+ res.kind = oREL -+ if aop.value is not None and bop.value is not None: -+ assert len(aop.value) == 1 -+ assert len(bop.value) == 1 -+ coords = do_box_funcs( -+ tIsectFuncs, aop.value[0], bop.value[0]) -+ relfa = aop.value[0].relflags -+ relfb = bop.value[0].relflags -+ if relfa == relfb: -+ res.value = [Ref3D(coords + relfa)] -+ else: -+ pass -+ spush(res) -+ if blah: print("tIsect post", stack, file=bk.logfile) -+ elif opcode == 0x10: # tList -+ if blah: print("tList pre", stack, file=bk.logfile) -+ assert len(stack) >= 2 -+ bop = stack.pop() -+ aop = stack.pop() -+ sym = ',' -+ rank = 80 ########## check ####### -+ otext = ''.join([ -+ '('[:aop.rank < rank], -+ aop.text, -+ ')'[:aop.rank < rank], -+ sym, -+ '('[:bop.rank < rank], -+ bop.text, -+ ')'[:bop.rank < rank], -+ ]) -+ res = Operand(oREF, None, rank, otext) -+ if bop.kind == oERR or aop.kind == oERR: -+ res.kind = oERR -+ elif bop.kind in (oREF, oREL) and aop.kind in (oREF, oREL): -+ res.kind = oREF -+ if aop.kind == oREL or bop.kind == oREL: -+ res.kind = oREL -+ if aop.value is not None and bop.value is not None: -+ assert len(aop.value) >= 1 -+ assert len(bop.value) == 1 -+ res.value = aop.value + bop.value -+ else: -+ pass -+ spush(res) -+ if blah: print("tList post", stack, file=bk.logfile) -+ elif opcode == 0x11: # tRange -+ if blah: print("tRange pre", stack, file=bk.logfile) -+ assert len(stack) >= 2 -+ bop = stack.pop() -+ aop = stack.pop() -+ sym = ':' -+ rank = 80 ########## check ####### -+ otext = ''.join([ -+ '('[:aop.rank < rank], -+ aop.text, -+ ')'[:aop.rank < rank], -+ sym, -+ '('[:bop.rank < rank], -+ bop.text, -+ ')'[:bop.rank < rank], -+ ]) -+ res = Operand(oREF, None, rank, otext) -+ if bop.kind == oERR or aop.kind == oERR: -+ res = oERR -+ elif bop.kind == oREF == aop.kind: -+ if aop.value is not None and bop.value is not None: -+ assert len(aop.value) == 1 -+ assert len(bop.value) == 1 -+ coords = do_box_funcs( -+ tRangeFuncs, aop.value[0], bop.value[0]) -+ res.value = [Ref3D(coords)] -+ elif bop.kind == oREL == aop.kind: -+ res.kind = oREL -+ if aop.value is not None and bop.value is not None: -+ assert len(aop.value) == 1 -+ assert len(bop.value) == 1 -+ coords = do_box_funcs( -+ tRangeFuncs, aop.value[0], bop.value[0]) -+ relfa = aop.value[0].relflags -+ relfb = bop.value[0].relflags -+ if relfa == relfb: -+ res.value = [Ref3D(coords + relfa)] -+ else: -+ pass -+ spush(res) -+ if blah: print("tRange post", stack, file=bk.logfile) -+ elif 0x12 <= opcode <= 0x14: # tUplus, tUminus, tPercent -+ do_unaryop(opcode, oNUM, stack) -+ elif opcode == 0x15: # tParen -+ # source cosmetics -+ pass -+ elif opcode == 0x16: # tMissArg -+ spush(Operand(oMSNG, None, LEAF_RANK, '')) -+ elif opcode == 0x17: # tStr -+ if bv <= 70: -+ strg, newpos = unpack_string_update_pos( -+ data, pos+1, bk.encoding, lenlen=1) -+ else: -+ strg, newpos = unpack_unicode_update_pos( -+ data, pos+1, lenlen=1) -+ sz = newpos - pos -+ if blah: print(" sz=%d strg=%r" % (sz, strg), file=bk.logfile) -+ text = '"' + strg.replace('"', '""') + '"' -+ spush(Operand(oSTRG, strg, LEAF_RANK, text)) -+ elif opcode == 0x18: # tExtended -+ # new with BIFF 8 -+ assert bv >= 80 -+ # not in OOo docs -+ raise FormulaError("tExtended token not implemented") -+ elif opcode == 0x19: # tAttr -+ subop, nc = unpack("= 1 -+ aop = stack[-1] -+ otext = 'SUM(%s)' % aop.text -+ stack[-1] = Operand(oNUM, None, FUNC_RANK, otext) -+ else: -+ sz = 4 -+ if blah: -+ print(" subop=%02xh subname=t%s sz=%d nc=%02xh" \ -+ % (subop, subname, sz, nc), file=bk.logfile) -+ elif 0x1A <= opcode <= 0x1B: # tSheet, tEndSheet -+ assert bv < 50 -+ raise FormulaError("tSheet & tEndsheet tokens not implemented") -+ elif 0x1C <= opcode <= 0x1F: # tErr, tBool, tInt, tNum -+ inx = opcode - 0x1C -+ nb = [1, 1, 2, 8][inx] -+ kind = [oERR, oBOOL, oNUM, oNUM][inx] -+ value, = unpack("<" + "BBHd"[inx], data[pos+1:pos+1+nb]) -+ if inx == 2: # tInt -+ value = float(value) -+ text = str(value) -+ elif inx == 3: # tNum -+ text = str(value) -+ elif inx == 1: # tBool -+ text = ('FALSE', 'TRUE')[value] -+ else: -+ text = '"' +error_text_from_code[value] + '"' -+ spush(Operand(kind, value, LEAF_RANK, text)) -+ else: -+ raise FormulaError("Unhandled opcode: 0x%02x" % opcode) -+ if sz <= 0: -+ raise FormulaError("Size not set for opcode 0x%02x" % opcode) -+ pos += sz -+ continue -+ if opcode == 0x00: # tArray -+ spush(unk_opnd) -+ elif opcode == 0x01: # tFunc -+ nb = 1 + int(bv >= 40) -+ funcx = unpack("<" + " BH"[nb], data[pos+1:pos+1+nb])[0] -+ func_attrs = func_defs.get(funcx, None) -+ if not func_attrs: -+ print("*** formula/tFunc unknown FuncID:%d" \ -+ % funcx, file=bk.logfile) -+ spush(unk_opnd) -+ else: -+ func_name, nargs = func_attrs[:2] -+ if blah: -+ print(" FuncID=%d name=%s nargs=%d" \ -+ % (funcx, func_name, nargs), file=bk.logfile) -+ assert len(stack) >= nargs -+ if nargs: -+ argtext = listsep.join([arg.text for arg in stack[-nargs:]]) -+ otext = "%s(%s)" % (func_name, argtext) -+ del stack[-nargs:] -+ else: -+ otext = func_name + "()" -+ res = Operand(oUNK, None, FUNC_RANK, otext) -+ spush(res) -+ elif opcode == 0x02: #tFuncVar -+ nb = 1 + int(bv >= 40) -+ nargs, funcx = unpack("= nargs -+ assert len(stack) >= nargs -+ argtext = listsep.join([arg.text for arg in stack[-nargs:]]) -+ otext = "%s(%s)" % (func_name, argtext) -+ res = Operand(oUNK, None, FUNC_RANK, otext) -+ if funcx == 1: # IF -+ testarg = stack[-nargs] -+ if testarg.kind not in (oNUM, oBOOL): -+ if blah and testarg.kind != oUNK: -+ print("IF testarg kind?", file=bk.logfile) -+ elif testarg.value not in (0, 1): -+ if blah and testarg.value is not None: -+ print("IF testarg value?", file=bk.logfile) -+ else: -+ if nargs == 2 and not testarg.value: -+ # IF(FALSE, tv) => FALSE -+ res.kind, res.value = oBOOL, 0 -+ else: -+ respos = -nargs + 2 - int(testarg.value) -+ chosen = stack[respos] -+ if chosen.kind == oMSNG: -+ res.kind, res.value = oNUM, 0 -+ else: -+ res.kind, res.value = chosen.kind, chosen.value -+ if blah: -+ print("$$$$$$ IF => constant", file=bk.logfile) -+ elif funcx == 100: # CHOOSE -+ testarg = stack[-nargs] -+ if testarg.kind == oNUM: -+ if 1 <= testarg.value < nargs: -+ chosen = stack[-nargs + int(testarg.value)] -+ if chosen.kind == oMSNG: -+ res.kind, res.value = oNUM, 0 -+ else: -+ res.kind, res.value = chosen.kind, chosen.value -+ del stack[-nargs:] -+ spush(res) -+ elif opcode == 0x03: #tName -+ tgtnamex = unpack("> bk.logfile, " ", res -+ # spush(res) -+ elif opcode == 0x0D: #tAreaN -+ not_in_name_formula(op, oname) -+ # res = get_cell_range_addr(data, pos+1, bv, reldelta=1) -+ # # note *ALL* tAreaN usage has signed offset for relative addresses -+ # any_rel = 1 -+ # if blah: print >> bk.logfile, " ", res -+ elif opcode == 0x1A: # tRef3d -+ if bv >= 80: -+ res = get_cell_addr(data, pos+3, bv, reldelta) -+ refx = unpack("= 80: -+ res1, res2 = get_cell_range_addr(data, pos+3, bv, reldelta) -+ refx = unpack("= 80: -+ refx, tgtnamex = unpack(" 0: -+ refx -= 1 -+ elif refx < 0: -+ refx = -refx - 1 -+ else: -+ dodgy = 1 -+ if blah: -+ print(" origrefx=%d refx=%d tgtnamex=%d dodgy=%d" \ -+ % (origrefx, refx, tgtnamex, dodgy), file=bk.logfile) -+ if tgtnamex == namex: -+ if blah: print("!!!! Self-referential !!!!", file=bk.logfile) -+ dodgy = any_err = 1 -+ if not dodgy: -+ if bv >= 80: -+ shx1, shx2 = get_externsheet_local_range(bk, refx, blah) -+ elif origrefx > 0: -+ shx1, shx2 = (-4, -4) # external ref -+ else: -+ exty = bk._externsheet_type_b57[refx] -+ if exty == 4: # non-specific sheet in own doc't -+ shx1, shx2 = (-1, -1) # internal, any sheet -+ else: -+ shx1, shx2 = (-666, -666) -+ if dodgy or shx1 < -1: -+ otext = "<>" \ -+ % (tgtnamex, origrefx) -+ res = Operand(oUNK, None, LEAF_RANK, otext) -+ else: -+ tgtobj = bk.name_obj_list[tgtnamex] -+ if not tgtobj.evaluated: -+ ### recursive ### -+ evaluate_name_formula(bk, tgtobj, tgtnamex, blah, level+1) -+ if tgtobj.macro or tgtobj.binary \ -+ or tgtobj.any_err: -+ if blah: -+ tgtobj.dump( -+ bk.logfile, -+ header="!!! bad tgtobj !!!", -+ footer="------------------", -+ ) -+ res = Operand(oUNK, None) -+ any_err = any_err or tgtobj.macro or tgtobj.binary or tgtobj.any_err -+ any_rel = any_rel or tgtobj.any_rel -+ else: -+ assert len(tgtobj.stack) == 1 -+ res = copy.deepcopy(tgtobj.stack[0]) -+ res.rank = LEAF_RANK -+ if tgtobj.scope == -1: -+ res.text = tgtobj.name -+ else: -+ res.text = "%s!%s" \ -+ % (bk._sheet_names[tgtobj.scope], tgtobj.name) -+ if blah: -+ print(" tNameX: setting text to", repr(res.text), file=bk.logfile) -+ spush(res) -+ elif opcode in error_opcodes: -+ any_err = 1 -+ spush(error_opnd) -+ else: -+ if blah: -+ print("FORMULA: /// Not handled yet: t" + oname, file=bk.logfile) -+ any_err = 1 -+ if sz <= 0: -+ raise FormulaError("Fatal: token size is not positive") -+ pos += sz -+ any_rel = not not any_rel -+ if blah: -+ fprintf(bk.logfile, "End of formula. level=%d any_rel=%d any_err=%d stack=%r\n", -+ level, not not any_rel, any_err, stack) -+ if len(stack) >= 2: -+ print("*** Stack has unprocessed args", file=bk.logfile) -+ print(file=bk.logfile) -+ nobj.stack = stack -+ if len(stack) != 1: -+ nobj.result = None -+ else: -+ nobj.result = stack[0] -+ nobj.any_rel = any_rel -+ nobj.any_err = any_err -+ nobj.any_external = any_external -+ nobj.evaluated = 1 -+ -+#### under construction ############################################################################# -+def decompile_formula(bk, fmla, fmlalen, -+ fmlatype=None, browx=None, bcolx=None, -+ blah=0, level=0, r1c1=0): -+ if level > STACK_ALARM_LEVEL: -+ blah = 1 -+ reldelta = fmlatype in (FMLA_TYPE_SHARED, FMLA_TYPE_NAME, FMLA_TYPE_COND_FMT, FMLA_TYPE_DATA_VAL) -+ data = fmla -+ bv = bk.biff_version -+ if blah: -+ print("::: decompile_formula len=%d fmlatype=%r browx=%r bcolx=%r reldelta=%d %r level=%d" \ -+ % (fmlalen, fmlatype, browx, bcolx, reldelta, data, level), file=bk.logfile) -+ hex_char_dump(data, 0, fmlalen, fout=bk.logfile) -+ if level > STACK_PANIC_LEVEL: -+ raise XLRDError("Excessive indirect references in formula") -+ sztab = szdict[bv] -+ pos = 0 -+ stack = [] -+ any_rel = 0 -+ any_err = 0 -+ any_external = 0 -+ unk_opnd = Operand(oUNK, None) -+ error_opnd = Operand(oERR, None) -+ spush = stack.append -+ -+ def do_binop(opcd, stk): -+ assert len(stk) >= 2 -+ bop = stk.pop() -+ aop = stk.pop() -+ argdict, result_kind, func, rank, sym = binop_rules[opcd] -+ otext = ''.join([ -+ '('[:aop.rank < rank], -+ aop.text, -+ ')'[:aop.rank < rank], -+ sym, -+ '('[:bop.rank < rank], -+ bop.text, -+ ')'[:bop.rank < rank], -+ ]) -+ resop = Operand(result_kind, None, rank, otext) -+ stk.append(resop) -+ -+ def do_unaryop(opcode, result_kind, stk): -+ assert len(stk) >= 1 -+ aop = stk.pop() -+ func, rank, sym1, sym2 = unop_rules[opcode] -+ otext = ''.join([ -+ sym1, -+ '('[:aop.rank < rank], -+ aop.text, -+ ')'[:aop.rank < rank], -+ sym2, -+ ]) -+ stk.append(Operand(result_kind, None, rank, otext)) -+ -+ def unexpected_opcode(op_arg, oname_arg): -+ msg = "ERROR *** Unexpected token 0x%02x (%s) found in formula type %s" \ -+ % (op_arg, oname_arg, FMLA_TYPEDESCR_MAP[fmlatype]) -+ print(msg, file=bk.logfile) -+ # raise FormulaError(msg) -+ -+ if fmlalen == 0: -+ stack = [unk_opnd] -+ -+ while 0 <= pos < fmlalen: -+ op = BYTES_ORD(data[pos]) -+ opcode = op & 0x1f -+ optype = (op & 0x60) >> 5 -+ if optype: -+ opx = opcode + 32 -+ else: -+ opx = opcode -+ oname = onames[opx] # + [" RVA"][optype] -+ sz = sztab[opx] -+ if blah: -+ print("Pos:%d Op:0x%02x opname:t%s Sz:%d opcode:%02xh optype:%02xh" \ -+ % (pos, op, oname, sz, opcode, optype), file=bk.logfile) -+ print("Stack =", stack, file=bk.logfile) -+ if sz == -2: -+ msg = 'ERROR *** Unexpected token 0x%02x ("%s"); biff_version=%d' \ -+ % (op, oname, bv) -+ raise FormulaError(msg) -+ if _TOKEN_NOT_ALLOWED(opx, 0) & fmlatype: -+ unexpected_opcode(op, oname) -+ if not optype: -+ if opcode <= 0x01: # tExp -+ if bv >= 30: -+ fmt = '= 2 -+ bop = stack.pop() -+ aop = stack.pop() -+ sym = ' ' -+ rank = 80 ########## check ####### -+ otext = ''.join([ -+ '('[:aop.rank < rank], -+ aop.text, -+ ')'[:aop.rank < rank], -+ sym, -+ '('[:bop.rank < rank], -+ bop.text, -+ ')'[:bop.rank < rank], -+ ]) -+ res = Operand(oREF) -+ res.text = otext -+ if bop.kind == oERR or aop.kind == oERR: -+ res.kind = oERR -+ elif bop.kind == oUNK or aop.kind == oUNK: -+ # This can happen with undefined -+ # (go search in the current sheet) labels. -+ # For example =Bob Sales -+ # Each label gets a NAME record with an empty formula (!) -+ # Evaluation of the tName token classifies it as oUNK -+ # res.kind = oREF -+ pass -+ elif bop.kind == oREF == aop.kind: -+ pass -+ elif bop.kind == oREL == aop.kind: -+ res.kind = oREL -+ else: -+ pass -+ spush(res) -+ if blah: print("tIsect post", stack, file=bk.logfile) -+ elif opcode == 0x10: # tList -+ if blah: print("tList pre", stack, file=bk.logfile) -+ assert len(stack) >= 2 -+ bop = stack.pop() -+ aop = stack.pop() -+ sym = ',' -+ rank = 80 ########## check ####### -+ otext = ''.join([ -+ '('[:aop.rank < rank], -+ aop.text, -+ ')'[:aop.rank < rank], -+ sym, -+ '('[:bop.rank < rank], -+ bop.text, -+ ')'[:bop.rank < rank], -+ ]) -+ res = Operand(oREF, None, rank, otext) -+ if bop.kind == oERR or aop.kind == oERR: -+ res.kind = oERR -+ elif bop.kind in (oREF, oREL) and aop.kind in (oREF, oREL): -+ res.kind = oREF -+ if aop.kind == oREL or bop.kind == oREL: -+ res.kind = oREL -+ else: -+ pass -+ spush(res) -+ if blah: print("tList post", stack, file=bk.logfile) -+ elif opcode == 0x11: # tRange -+ if blah: print("tRange pre", stack, file=bk.logfile) -+ assert len(stack) >= 2 -+ bop = stack.pop() -+ aop = stack.pop() -+ sym = ':' -+ rank = 80 ########## check ####### -+ otext = ''.join([ -+ '('[:aop.rank < rank], -+ aop.text, -+ ')'[:aop.rank < rank], -+ sym, -+ '('[:bop.rank < rank], -+ bop.text, -+ ')'[:bop.rank < rank], -+ ]) -+ res = Operand(oREF, None, rank, otext) -+ if bop.kind == oERR or aop.kind == oERR: -+ res = oERR -+ elif bop.kind == oREF == aop.kind: -+ pass -+ else: -+ pass -+ spush(res) -+ if blah: print("tRange post", stack, file=bk.logfile) -+ elif 0x12 <= opcode <= 0x14: # tUplus, tUminus, tPercent -+ do_unaryop(opcode, oNUM, stack) -+ elif opcode == 0x15: # tParen -+ # source cosmetics -+ pass -+ elif opcode == 0x16: # tMissArg -+ spush(Operand(oMSNG, None, LEAF_RANK, '')) -+ elif opcode == 0x17: # tStr -+ if bv <= 70: -+ strg, newpos = unpack_string_update_pos( -+ data, pos+1, bk.encoding, lenlen=1) -+ else: -+ strg, newpos = unpack_unicode_update_pos( -+ data, pos+1, lenlen=1) -+ sz = newpos - pos -+ if blah: print(" sz=%d strg=%r" % (sz, strg), file=bk.logfile) -+ text = '"' + strg.replace('"', '""') + '"' -+ spush(Operand(oSTRG, None, LEAF_RANK, text)) -+ elif opcode == 0x18: # tExtended -+ # new with BIFF 8 -+ assert bv >= 80 -+ # not in OOo docs, don't even know how to determine its length -+ raise FormulaError("tExtended token not implemented") -+ elif opcode == 0x19: # tAttr -+ subop, nc = unpack("= 1 -+ aop = stack[-1] -+ otext = 'SUM(%s)' % aop.text -+ stack[-1] = Operand(oNUM, None, FUNC_RANK, otext) -+ else: -+ sz = 4 -+ if blah: -+ print(" subop=%02xh subname=t%s sz=%d nc=%02xh" \ -+ % (subop, subname, sz, nc), file=bk.logfile) -+ elif 0x1A <= opcode <= 0x1B: # tSheet, tEndSheet -+ assert bv < 50 -+ raise FormulaError("tSheet & tEndsheet tokens not implemented") -+ elif 0x1C <= opcode <= 0x1F: # tErr, tBool, tInt, tNum -+ inx = opcode - 0x1C -+ nb = [1, 1, 2, 8][inx] -+ kind = [oERR, oBOOL, oNUM, oNUM][inx] -+ value, = unpack("<" + "BBHd"[inx], data[pos+1:pos+1+nb]) -+ if inx == 2: # tInt -+ value = float(value) -+ text = str(value) -+ elif inx == 3: # tNum -+ text = str(value) -+ elif inx == 1: # tBool -+ text = ('FALSE', 'TRUE')[value] -+ else: -+ text = '"' +error_text_from_code[value] + '"' -+ spush(Operand(kind, None, LEAF_RANK, text)) -+ else: -+ raise FormulaError("Unhandled opcode: 0x%02x" % opcode) -+ if sz <= 0: -+ raise FormulaError("Size not set for opcode 0x%02x" % opcode) -+ pos += sz -+ continue -+ if opcode == 0x00: # tArray -+ spush(unk_opnd) -+ elif opcode == 0x01: # tFunc -+ nb = 1 + int(bv >= 40) -+ funcx = unpack("<" + " BH"[nb], data[pos+1:pos+1+nb])[0] -+ func_attrs = func_defs.get(funcx, None) -+ if not func_attrs: -+ print("*** formula/tFunc unknown FuncID:%d" % funcx, file=bk.logfile) -+ spush(unk_opnd) -+ else: -+ func_name, nargs = func_attrs[:2] -+ if blah: -+ print(" FuncID=%d name=%s nargs=%d" \ -+ % (funcx, func_name, nargs), file=bk.logfile) -+ assert len(stack) >= nargs -+ if nargs: -+ argtext = listsep.join([arg.text for arg in stack[-nargs:]]) -+ otext = "%s(%s)" % (func_name, argtext) -+ del stack[-nargs:] -+ else: -+ otext = func_name + "()" -+ res = Operand(oUNK, None, FUNC_RANK, otext) -+ spush(res) -+ elif opcode == 0x02: #tFuncVar -+ nb = 1 + int(bv >= 40) -+ nargs, funcx = unpack("= nargs -+ assert len(stack) >= nargs -+ argtext = listsep.join([arg.text for arg in stack[-nargs:]]) -+ otext = "%s(%s)" % (func_name, argtext) -+ res = Operand(oUNK, None, FUNC_RANK, otext) -+ del stack[-nargs:] -+ spush(res) -+ elif opcode == 0x03: #tName -+ tgtnamex = unpack("> bk.logfile, " ", res -+ res1, res2 = get_cell_range_addr( -+ data, pos+1, bv, reldelta, browx, bcolx) -+ if blah: print(" ", res1, res2, file=bk.logfile) -+ rowx1, colx1, row_rel1, col_rel1 = res1 -+ rowx2, colx2, row_rel2, col_rel2 = res2 -+ coords = (rowx1, rowx2+1, colx1, colx2+1) -+ relflags = (row_rel1, row_rel2, col_rel1, col_rel2) -+ if sum(relflags): # relative -+ okind = oREL -+ else: -+ okind = oREF -+ if blah: print(" ", coords, relflags, file=bk.logfile) -+ otext = rangename2drel(coords, relflags, browx, bcolx, r1c1) -+ res = Operand(okind, None, LEAF_RANK, otext) -+ spush(res) -+ elif opcode == 0x1A: # tRef3d -+ if bv >= 80: -+ res = get_cell_addr(data, pos+3, bv, reldelta, browx, bcolx) -+ refx = unpack("= 80: -+ res1, res2 = get_cell_range_addr(data, pos+3, bv, reldelta) -+ refx = unpack("= 80: -+ refx, tgtnamex = unpack(" 0: -+ refx -= 1 -+ elif refx < 0: -+ refx = -refx - 1 -+ else: -+ dodgy = 1 -+ if blah: -+ print(" origrefx=%d refx=%d tgtnamex=%d dodgy=%d" \ -+ % (origrefx, refx, tgtnamex, dodgy), file=bk.logfile) -+ # if tgtnamex == namex: -+ # if blah: print >> bk.logfile, "!!!! Self-referential !!!!" -+ # dodgy = any_err = 1 -+ if not dodgy: -+ if bv >= 80: -+ shx1, shx2 = get_externsheet_local_range(bk, refx, blah) -+ elif origrefx > 0: -+ shx1, shx2 = (-4, -4) # external ref -+ else: -+ exty = bk._externsheet_type_b57[refx] -+ if exty == 4: # non-specific sheet in own doc't -+ shx1, shx2 = (-1, -1) # internal, any sheet -+ else: -+ shx1, shx2 = (-666, -666) -+ okind = oUNK -+ ovalue = None -+ if shx1 == -5: # addin func name -+ okind = oSTRG -+ ovalue = bk.addin_func_names[tgtnamex] -+ otext = '"' + ovalue.replace('"', '""') + '"' -+ elif dodgy or shx1 < -1: -+ otext = "<>" \ -+ % (tgtnamex, origrefx) -+ else: -+ tgtobj = bk.name_obj_list[tgtnamex] -+ if tgtobj.scope == -1: -+ otext = tgtobj.name -+ else: -+ otext = "%s!%s" \ -+ % (bk._sheet_names[tgtobj.scope], tgtobj.name) -+ if blah: -+ print(" tNameX: setting text to", repr(res.text), file=bk.logfile) -+ res = Operand(okind, ovalue, LEAF_RANK, otext) -+ spush(res) -+ elif opcode in error_opcodes: -+ any_err = 1 -+ spush(error_opnd) -+ else: -+ if blah: -+ print("FORMULA: /// Not handled yet: t" + oname, file=bk.logfile) -+ any_err = 1 -+ if sz <= 0: -+ raise FormulaError("Fatal: token size is not positive") -+ pos += sz -+ any_rel = not not any_rel -+ if blah: -+ print("End of formula. level=%d any_rel=%d any_err=%d stack=%r" % \ -+ (level, not not any_rel, any_err, stack), file=bk.logfile) -+ if len(stack) >= 2: -+ print("*** Stack has unprocessed args", file=bk.logfile) -+ print(file=bk.logfile) -+ -+ if len(stack) != 1: -+ result = None -+ else: -+ result = stack[0].text -+ return result -+ -+#### under deconstruction ### -+def dump_formula(bk, data, fmlalen, bv, reldelta, blah=0, isname=0): -+ if blah: -+ print("dump_formula", fmlalen, bv, len(data), file=bk.logfile) -+ hex_char_dump(data, 0, fmlalen, fout=bk.logfile) -+ assert bv >= 80 #### this function needs updating #### -+ sztab = szdict[bv] -+ pos = 0 -+ stack = [] -+ any_rel = 0 -+ any_err = 0 -+ spush = stack.append -+ while 0 <= pos < fmlalen: -+ op = BYTES_ORD(data[pos]) -+ opcode = op & 0x1f -+ optype = (op & 0x60) >> 5 -+ if optype: -+ opx = opcode + 32 -+ else: -+ opx = opcode -+ oname = onames[opx] # + [" RVA"][optype] -+ -+ sz = sztab[opx] -+ if blah: -+ print("Pos:%d Op:0x%02x Name:t%s Sz:%d opcode:%02xh optype:%02xh" \ -+ % (pos, op, oname, sz, opcode, optype), file=bk.logfile) -+ if not optype: -+ if 0x01 <= opcode <= 0x02: # tExp, tTbl -+ # reference to a shared formula or table record -+ rowx, colx = unpack("= 2 -+ bop = stack.pop() -+ aop = stack.pop() -+ spush(aop + bop) -+ if blah: print("tlist post", stack, file=bk.logfile) -+ elif opcode == 0x11: # tRange -+ if blah: print("tRange pre", stack, file=bk.logfile) -+ assert len(stack) >= 2 -+ bop = stack.pop() -+ aop = stack.pop() -+ assert len(aop) == 1 -+ assert len(bop) == 1 -+ result = do_box_funcs(tRangeFuncs, aop[0], bop[0]) -+ spush(result) -+ if blah: print("tRange post", stack, file=bk.logfile) -+ elif opcode == 0x0F: # tIsect -+ if blah: print("tIsect pre", stack, file=bk.logfile) -+ assert len(stack) >= 2 -+ bop = stack.pop() -+ aop = stack.pop() -+ assert len(aop) == 1 -+ assert len(bop) == 1 -+ result = do_box_funcs(tIsectFuncs, aop[0], bop[0]) -+ spush(result) -+ if blah: print("tIsect post", stack, file=bk.logfile) -+ elif opcode == 0x19: # tAttr -+ subop, nc = unpack("= 40) -+ funcx = unpack("<" + " BH"[nb], data[pos+1:pos+1+nb]) -+ if blah: print(" FuncID=%d" % funcx, file=bk.logfile) -+ elif opcode == 0x02: #tFuncVar -+ nb = 1 + int(bv >= 40) -+ nargs, funcx = unpack("= 2: -+ print("*** Stack has unprocessed args", file=bk.logfile) -+ -+# === Some helper functions for displaying cell references === -+ -+# I'm aware of only one possibility of a sheet-relative component in -+# a reference: a 2D reference located in the "current sheet". -+# xlrd stores this internally with bounds of (0, 1, ...) and -+# relative flags of (1, 1, ...). These functions display the -+# sheet component as empty, just like Excel etc. -+ -+def rownamerel(rowx, rowxrel, browx=None, r1c1=0): -+ # if no base rowx is provided, we have to return r1c1 -+ if browx is None: -+ r1c1 = True -+ if not rowxrel: -+ if r1c1: -+ return "R%d" % (rowx+1) -+ return "$%d" % (rowx+1) -+ if r1c1: -+ if rowx: -+ return "R[%d]" % rowx -+ return "R" -+ return "%d" % ((browx + rowx) % 65536 + 1) -+ -+def colnamerel(colx, colxrel, bcolx=None, r1c1=0): -+ # if no base colx is provided, we have to return r1c1 -+ if bcolx is None: -+ r1c1 = True -+ if not colxrel: -+ if r1c1: -+ return "C%d" % (colx + 1) -+ return "$" + colname(colx) -+ if r1c1: -+ if colx: -+ return "C[%d]" % colx -+ return "C" -+ return colname((bcolx + colx) % 256) -+ -+## -+# Utility function: (5, 7) => 'H6' -+def cellname(rowx, colx): -+ """ (5, 7) => 'H6' """ -+ return "%s%d" % (colname(colx), rowx+1) -+ -+## -+# Utility function: (5, 7) => '$H$6' -+def cellnameabs(rowx, colx, r1c1=0): -+ """ (5, 7) => '$H$6' or 'R8C6'""" -+ if r1c1: -+ return "R%dC%d" % (rowx+1, colx+1) -+ return "$%s$%d" % (colname(colx), rowx+1) -+ -+def cellnamerel(rowx, colx, rowxrel, colxrel, browx=None, bcolx=None, r1c1=0): -+ if not rowxrel and not colxrel: -+ return cellnameabs(rowx, colx, r1c1) -+ if (rowxrel and browx is None) or (colxrel and bcolx is None): -+ # must flip the whole cell into R1C1 mode -+ r1c1 = True -+ c = colnamerel(colx, colxrel, bcolx, r1c1) -+ r = rownamerel(rowx, rowxrel, browx, r1c1) -+ if r1c1: -+ return r + c -+ return c + r -+ -+## -+# Utility function: 7 => 'H', 27 => 'AB' -+def colname(colx): -+ """ 7 => 'H', 27 => 'AB' """ -+ alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -+ if colx <= 25: -+ return alphabet[colx] -+ else: -+ xdiv26, xmod26 = divmod(colx, 26) -+ return alphabet[xdiv26 - 1] + alphabet[xmod26] -+ -+def rangename2d(rlo, rhi, clo, chi, r1c1=0): -+ """ (5, 20, 7, 10) => '$H$6:$J$20' """ -+ if r1c1: -+ return -+ if rhi == rlo+1 and chi == clo+1: -+ return cellnameabs(rlo, clo, r1c1) -+ return "%s:%s" % (cellnameabs(rlo, clo, r1c1), cellnameabs(rhi-1, chi-1, r1c1)) -+ -+def rangename2drel(rlo_rhi_clo_chi, rlorel_rhirel_clorel_chirel, browx=None, bcolx=None, r1c1=0): -+ rlo, rhi, clo, chi = rlo_rhi_clo_chi -+ rlorel, rhirel, clorel, chirel = rlorel_rhirel_clorel_chirel -+ if (rlorel or rhirel) and browx is None: -+ r1c1 = True -+ if (clorel or chirel) and bcolx is None: -+ r1c1 = True -+ return "%s:%s" % ( -+ cellnamerel(rlo, clo, rlorel, clorel, browx, bcolx, r1c1), -+ cellnamerel(rhi-1, chi-1, rhirel, chirel, browx, bcolx, r1c1) -+ ) -+## -+# Utility function: -+#
Ref3D((1, 4, 5, 20, 7, 10)) => 'Sheet2:Sheet3!$H$6:$J$20' -+def rangename3d(book, ref3d): -+ """ Ref3D(1, 4, 5, 20, 7, 10) => 'Sheet2:Sheet3!$H$6:$J$20' -+ (assuming Excel's default sheetnames) """ -+ coords = ref3d.coords -+ return "%s!%s" % ( -+ sheetrange(book, *coords[:2]), -+ rangename2d(*coords[2:6])) -+ -+## -+# Utility function: -+#
Ref3D(coords=(0, 1, -32, -22, -13, 13), relflags=(0, 0, 1, 1, 1, 1)) -+# R1C1 mode => 'Sheet1!R[-32]C[-13]:R[-23]C[12]' -+# A1 mode => depends on base cell (browx, bcolx) -+def rangename3drel(book, ref3d, browx=None, bcolx=None, r1c1=0): -+ coords = ref3d.coords -+ relflags = ref3d.relflags -+ shdesc = sheetrangerel(book, coords[:2], relflags[:2]) -+ rngdesc = rangename2drel(coords[2:6], relflags[2:6], browx, bcolx, r1c1) -+ if not shdesc: -+ return rngdesc -+ return "%s!%s" % (shdesc, rngdesc) -+ -+def quotedsheetname(shnames, shx): -+ if shx >= 0: -+ shname = shnames[shx] -+ else: -+ shname = { -+ -1: "?internal; any sheet?", -+ -2: "internal; deleted sheet", -+ -3: "internal; macro sheet", -+ -4: "<>", -+ }.get(shx, "?error %d?" % shx) -+ if "'" in shname: -+ return "'" + shname.replace("'", "''") + "'" -+ if " " in shname: -+ return "'" + shname + "'" -+ return shname -+ -+def sheetrange(book, slo, shi): -+ shnames = book.sheet_names() -+ shdesc = quotedsheetname(shnames, slo) -+ if slo != shi-1: -+ shdesc += ":" + quotedsheetname(shnames, shi-1) -+ return shdesc -+ -+def sheetrangerel(book, srange, srangerel): -+ slo, shi = srange -+ slorel, shirel = srangerel -+ if not slorel and not shirel: -+ return sheetrange(book, slo, shi) -+ assert (slo == 0 == shi-1) and slorel and shirel -+ return "" -+ -+# ============================================================== -diff --git a/webhub/xlrd/formula.pyc b/webhub/xlrd/formula.pyc -new file mode 100644 -index 0000000..0a14b04 -Binary files /dev/null and b/webhub/xlrd/formula.pyc differ -diff --git a/webhub/xlrd/info.py b/webhub/xlrd/info.py -new file mode 100644 -index 0000000..528a2b4 ---- /dev/null -+++ b/webhub/xlrd/info.py -@@ -0,0 +1 @@ -+__VERSION__ = "0.9.3" -diff --git a/webhub/xlrd/info.pyc b/webhub/xlrd/info.pyc -new file mode 100644 -index 0000000..288d889 -Binary files /dev/null and b/webhub/xlrd/info.pyc differ -diff --git a/webhub/xlrd/licences.py b/webhub/xlrd/licences.py -new file mode 100644 -index 0000000..1e262a9 ---- /dev/null -+++ b/webhub/xlrd/licences.py -@@ -0,0 +1,77 @@ -+# -*- coding: cp1252 -*- -+ -+""" -+Portions copyright 2005-2009, Stephen John Machin, Lingfo Pty Ltd -+All rights reserved. -+ -+Redistribution and use in source and binary forms, with or without -+modification, are permitted provided that the following conditions are met: -+ -+1. Redistributions of source code must retain the above copyright notice, -+this list of conditions and the following disclaimer. -+ -+2. Redistributions in binary form must reproduce the above copyright notice, -+this list of conditions and the following disclaimer in the documentation -+and/or other materials provided with the distribution. -+ -+3. None of the names of Stephen John Machin, Lingfo Pty Ltd and any -+contributors may be used to endorse or promote products derived from this -+software without specific prior written permission. -+ -+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -+THE POSSIBILITY OF SUCH DAMAGE. -+""" -+ -+""" -+/*- -+ * Copyright (c) 2001 David Giffin. -+ * All rights reserved. -+ * -+ * Based on the the Java version: Andrew Khan Copyright (c) 2000. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in -+ * the documentation and/or other materials provided with the -+ * distribution. -+ * -+ * 3. All advertising materials mentioning features or use of this -+ * software must display the following acknowledgment: -+ * "This product includes software developed by -+ * David Giffin ." -+ * -+ * 4. Redistributions of any form whatsoever must retain the following -+ * acknowledgment: -+ * "This product includes software developed by -+ * David Giffin ." -+ * -+ * THIS SOFTWARE IS PROVIDED BY DAVID GIFFIN ``AS IS'' AND ANY -+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID GIFFIN OR -+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -+ * OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+""" -diff --git a/webhub/xlrd/licences.pyc b/webhub/xlrd/licences.pyc -new file mode 100644 -index 0000000..aa5609c -Binary files /dev/null and b/webhub/xlrd/licences.pyc differ -diff --git a/webhub/xlrd/sheet.py b/webhub/xlrd/sheet.py -new file mode 100644 -index 0000000..36438a0 ---- /dev/null -+++ b/webhub/xlrd/sheet.py -@@ -0,0 +1,2419 @@ -+# -*- coding: cp1252 -*- -+ -+## -+#

Portions copyright 2005-2013 Stephen John Machin, Lingfo Pty Ltd

-+#

This module is part of the xlrd package, which is released under a BSD-style licence.

-+## -+ -+# 2010-04-25 SJM fix zoom factors cooking logic -+# 2010-04-15 CW r4253 fix zoom factors cooking logic -+# 2010-04-09 CW r4248 add a flag so xlutils knows whether or not to write a PANE record -+# 2010-03-29 SJM Fixed bug in adding new empty rows in put_cell_ragged -+# 2010-03-28 SJM Tailored put_cell method for each of ragged_rows=False (fixed speed regression) and =True (faster) -+# 2010-03-25 CW r4236 Slight refactoring to remove method calls -+# 2010-03-25 CW r4235 Collapse expand_cells into put_cell and enhance the raggedness. This should save even more memory! -+# 2010-03-25 CW r4234 remove duplicate chunks for extend_cells; refactor to remove put_number_cell and put_blank_cell which essentially duplicated the code of put_cell -+# 2010-03-10 SJM r4222 Added reading of the PANE record. -+# 2010-03-10 SJM r4221 Preliminary work on "cooked" mag factors; use at own peril -+# 2010-03-01 SJM Reading SCL record -+# 2010-03-01 SJM Added ragged_rows functionality -+# 2009-08-23 SJM Reduced CPU time taken by parsing MULBLANK records. -+# 2009-08-18 SJM Used __slots__ and sharing to reduce memory consumed by Rowinfo instances -+# 2009-05-31 SJM Fixed problem with no CODEPAGE record on extremely minimal BIFF2.x 3rd-party file -+# 2009-04-27 SJM Integrated on_demand patch by Armando Serrano Lombillo -+# 2008-02-09 SJM Excel 2.0: build XFs on the fly from cell attributes -+# 2007-12-04 SJM Added support for Excel 2.x (BIFF2) files. -+# 2007-10-11 SJM Added missing entry for blank cell type to ctype_text -+# 2007-07-11 SJM Allow for BIFF2/3-style FORMAT record in BIFF4/8 file -+# 2007-04-22 SJM Remove experimental "trimming" facility. -+ -+from __future__ import print_function -+ -+from array import array -+from struct import unpack, calcsize -+from .biffh import * -+from .timemachine import * -+from .formula import dump_formula, decompile_formula, rangename2d, FMLA_TYPE_CELL, FMLA_TYPE_SHARED -+from .formatting import nearest_colour_index, Format -+ -+DEBUG = 0 -+OBJ_MSO_DEBUG = 0 -+ -+_WINDOW2_options = ( -+ # Attribute names and initial values to use in case -+ # a WINDOW2 record is not written. -+ ("show_formulas", 0), -+ ("show_grid_lines", 1), -+ ("show_sheet_headers", 1), -+ ("panes_are_frozen", 0), -+ ("show_zero_values", 1), -+ ("automatic_grid_line_colour", 1), -+ ("columns_from_right_to_left", 0), -+ ("show_outline_symbols", 1), -+ ("remove_splits_if_pane_freeze_is_removed", 0), -+ # Multiple sheets can be selected, but only one can be active -+ # (hold down Ctrl and click multiple tabs in the file in OOo) -+ ("sheet_selected", 0), -+ # "sheet_visible" should really be called "sheet_active" -+ # and is 1 when this sheet is the sheet displayed when the file -+ # is open. More than likely only one sheet should ever be set as -+ # visible. -+ # This would correspond to the Book's sheet_active attribute, but -+ # that doesn't exist as WINDOW1 records aren't currently processed. -+ # The real thing is the visibility attribute from the BOUNDSHEET record. -+ ("sheet_visible", 0), -+ ("show_in_page_break_preview", 0), -+ ) -+ -+## -+#

Contains the data for one worksheet.

-+# -+#

In the cell access functions, "rowx" is a row index, counting from zero, and "colx" is a -+# column index, counting from zero. -+# Negative values for row/column indexes and slice positions are supported in the expected fashion.

-+# -+#

For information about cell types and cell values, refer to the documentation of the {@link #Cell} class.

-+# -+#

WARNING: You don't call this class yourself. You access Sheet objects via the Book object that -+# was returned when you called xlrd.open_workbook("myfile.xls").

-+ -+ -+class Sheet(BaseObject): -+ ## -+ # Name of sheet. -+ name = '' -+ -+ ## -+ # A reference to the Book object to which this sheet belongs. -+ # Example usage: some_sheet.book.datemode -+ book = None -+ -+ ## -+ # Number of rows in sheet. A row index is in range(thesheet.nrows). -+ nrows = 0 -+ -+ ## -+ # Nominal number of columns in sheet. It is 1 + the maximum column index -+ # found, ignoring trailing empty cells. See also open_workbook(ragged_rows=?) -+ # and Sheet.{@link #Sheet.row_len}(row_index). -+ ncols = 0 -+ -+ ## -+ # The map from a column index to a {@link #Colinfo} object. Often there is an entry -+ # in COLINFO records for all column indexes in range(257). -+ # Note that xlrd ignores the entry for the non-existent -+ # 257th column. On the other hand, there may be no entry for unused columns. -+ #
-- New in version 0.6.1. Populated only if open_workbook(formatting_info=True). -+ colinfo_map = {} -+ -+ ## -+ # The map from a row index to a {@link #Rowinfo} object. Note that it is possible -+ # to have missing entries -- at least one source of XLS files doesn't -+ # bother writing ROW records. -+ #
-- New in version 0.6.1. Populated only if open_workbook(formatting_info=True). -+ rowinfo_map = {} -+ -+ ## -+ # List of address ranges of cells containing column labels. -+ # These are set up in Excel by Insert > Name > Labels > Columns. -+ #
-- New in version 0.6.0 -+ #
How to deconstruct the list: -+ #
-+    # for crange in thesheet.col_label_ranges:
-+    #     rlo, rhi, clo, chi = crange
-+    #     for rx in xrange(rlo, rhi):
-+    #         for cx in xrange(clo, chi):
-+    #             print "Column label at (rowx=%d, colx=%d) is %r" \
-+    #                 (rx, cx, thesheet.cell_value(rx, cx))
-+    # 
-+ col_label_ranges = [] -+ -+ ## -+ # List of address ranges of cells containing row labels. -+ # For more details, see col_label_ranges above. -+ #
-- New in version 0.6.0 -+ row_label_ranges = [] -+ -+ ## -+ # List of address ranges of cells which have been merged. -+ # These are set up in Excel by Format > Cells > Alignment, then ticking -+ # the "Merge cells" box. -+ #
-- New in version 0.6.1. Extracted only if open_workbook(formatting_info=True). -+ #
How to deconstruct the list: -+ #
-+    # for crange in thesheet.merged_cells:
-+    #     rlo, rhi, clo, chi = crange
-+    #     for rowx in xrange(rlo, rhi):
-+    #         for colx in xrange(clo, chi):
-+    #             # cell (rlo, clo) (the top left one) will carry the data
-+    #             # and formatting info; the remainder will be recorded as
-+    #             # blank cells, but a renderer will apply the formatting info
-+    #             # for the top left cell (e.g. border, pattern) to all cells in
-+    #             # the range.
-+    # 
-+ merged_cells = [] -+ -+ ## -+ # Mapping of (rowx, colx) to list of (offset, font_index) tuples. The offset -+ # defines where in the string the font begins to be used. -+ # Offsets are expected to be in ascending order. -+ # If the first offset is not zero, the meaning is that the cell's XF's font should -+ # be used from offset 0. -+ #
This is a sparse mapping. There is no entry for cells that are not formatted with -+ # rich text. -+ #
How to use: -+ #
-+    # runlist = thesheet.rich_text_runlist_map.get((rowx, colx))
-+    # if runlist:
-+    #     for offset, font_index in runlist:
-+    #         # do work here.
-+    #         pass
-+    # 
-+ # Populated only if open_workbook(formatting_info=True). -+ #
-- New in version 0.7.2. -+ #
  -+ rich_text_runlist_map = {} -+ -+ ## -+ # Default column width from DEFCOLWIDTH record, else None. -+ # From the OOo docs:
-+ # """Column width in characters, using the width of the zero character -+ # from default font (first FONT record in the file). Excel adds some -+ # extra space to the default width, depending on the default font and -+ # default font size. The algorithm how to exactly calculate the resulting -+ # column width is not known.
-+ # Example: The default width of 8 set in this record results in a column -+ # width of 8.43 using Arial font with a size of 10 points."""
-+ # For the default hierarchy, refer to the {@link #Colinfo} class. -+ #
-- New in version 0.6.1 -+ defcolwidth = None -+ -+ ## -+ # Default column width from STANDARDWIDTH record, else None. -+ # From the OOo docs:
-+ # """Default width of the columns in 1/256 of the width of the zero -+ # character, using default font (first FONT record in the file)."""
-+ # For the default hierarchy, refer to the {@link #Colinfo} class. -+ #
-- New in version 0.6.1 -+ standardwidth = None -+ -+ ## -+ # Default value to be used for a row if there is -+ # no ROW record for that row. -+ # From the optional DEFAULTROWHEIGHT record. -+ default_row_height = None -+ -+ ## -+ # Default value to be used for a row if there is -+ # no ROW record for that row. -+ # From the optional DEFAULTROWHEIGHT record. -+ default_row_height_mismatch = None -+ -+ ## -+ # Default value to be used for a row if there is -+ # no ROW record for that row. -+ # From the optional DEFAULTROWHEIGHT record. -+ default_row_hidden = None -+ -+ ## -+ # Default value to be used for a row if there is -+ # no ROW record for that row. -+ # From the optional DEFAULTROWHEIGHT record. -+ default_additional_space_above = None -+ -+ ## -+ # Default value to be used for a row if there is -+ # no ROW record for that row. -+ # From the optional DEFAULTROWHEIGHT record. -+ default_additional_space_below = None -+ -+ ## -+ # Visibility of the sheet. 0 = visible, 1 = hidden (can be unhidden -+ # by user -- Format/Sheet/Unhide), 2 = "very hidden" (can be unhidden -+ # only by VBA macro). -+ visibility = 0 -+ -+ ## -+ # A 256-element tuple corresponding to the contents of the GCW record for this sheet. -+ # If no such record, treat as all bits zero. -+ # Applies to BIFF4-7 only. See docs of the {@link #Colinfo} class for discussion. -+ gcw = (0, ) * 256 -+ -+ ## -+ #

A list of {@link #Hyperlink} objects corresponding to HLINK records found -+ # in the worksheet.
-- New in version 0.7.2

-+ hyperlink_list = [] -+ -+ ## -+ #

A sparse mapping from (rowx, colx) to an item in {@link #Sheet.hyperlink_list}. -+ # Cells not covered by a hyperlink are not mapped. -+ # It is possible using the Excel UI to set up a hyperlink that -+ # covers a larger-than-1x1 rectangle of cells. -+ # Hyperlink rectangles may overlap (Excel doesn't check). -+ # When a multiply-covered cell is clicked on, the hyperlink that is activated -+ # (and the one that is mapped here) is the last in hyperlink_list. -+ #
-- New in version 0.7.2

-+ hyperlink_map = {} -+ -+ ## -+ #

A sparse mapping from (rowx, colx) to a {@link #Note} object. -+ # Cells not containing a note ("comment") are not mapped. -+ #
-- New in version 0.7.2

-+ cell_note_map = {} -+ -+ ## -+ # Number of columns in left pane (frozen panes; for split panes, see comments below in code) -+ vert_split_pos = 0 -+ -+ ## -+ # Number of rows in top pane (frozen panes; for split panes, see comments below in code) -+ horz_split_pos = 0 -+ -+ ## -+ # Index of first visible row in bottom frozen/split pane -+ horz_split_first_visible = 0 -+ -+ ## -+ # Index of first visible column in right frozen/split pane -+ vert_split_first_visible = 0 -+ -+ ## -+ # Frozen panes: ignore it. Split panes: explanation and diagrams in OOo docs. -+ split_active_pane = 0 -+ -+ ## -+ # Boolean specifying if a PANE record was present, ignore unless you're xlutils.copy -+ has_pane_record = 0 -+ -+ ## -+ # A list of the horizontal page breaks in this sheet. -+ # Breaks are tuples in the form (index of row after break, start col index, end col index). -+ # Populated only if open_workbook(formatting_info=True). -+ #
-- New in version 0.7.2 -+ horizontal_page_breaks = [] -+ -+ ## -+ # A list of the vertical page breaks in this sheet. -+ # Breaks are tuples in the form (index of col after break, start row index, end row index). -+ # Populated only if open_workbook(formatting_info=True). -+ #
-- New in version 0.7.2 -+ vertical_page_breaks = [] -+ -+ -+ def __init__(self, book, position, name, number): -+ self.book = book -+ self.biff_version = book.biff_version -+ self._position = position -+ self.logfile = book.logfile -+ self.bt = array('B', [XL_CELL_EMPTY]) -+ self.bf = array('h', [-1]) -+ self.name = name -+ self.number = number -+ self.verbosity = book.verbosity -+ self.formatting_info = book.formatting_info -+ self.ragged_rows = book.ragged_rows -+ if self.ragged_rows: -+ self.put_cell = self.put_cell_ragged -+ else: -+ self.put_cell = self.put_cell_unragged -+ self._xf_index_to_xl_type_map = book._xf_index_to_xl_type_map -+ self.nrows = 0 # actual, including possibly empty cells -+ self.ncols = 0 -+ self._maxdatarowx = -1 # highest rowx containing a non-empty cell -+ self._maxdatacolx = -1 # highest colx containing a non-empty cell -+ self._dimnrows = 0 # as per DIMENSIONS record -+ self._dimncols = 0 -+ self._cell_values = [] -+ self._cell_types = [] -+ self._cell_xf_indexes = [] -+ self.defcolwidth = None -+ self.standardwidth = None -+ self.default_row_height = None -+ self.default_row_height_mismatch = 0 -+ self.default_row_hidden = 0 -+ self.default_additional_space_above = 0 -+ self.default_additional_space_below = 0 -+ self.colinfo_map = {} -+ self.rowinfo_map = {} -+ self.col_label_ranges = [] -+ self.row_label_ranges = [] -+ self.merged_cells = [] -+ self.rich_text_runlist_map = {} -+ self.horizontal_page_breaks = [] -+ self.vertical_page_breaks = [] -+ self._xf_index_stats = [0, 0, 0, 0] -+ self.visibility = book._sheet_visibility[number] # from BOUNDSHEET record -+ for attr, defval in _WINDOW2_options: -+ setattr(self, attr, defval) -+ self.first_visible_rowx = 0 -+ self.first_visible_colx = 0 -+ self.gridline_colour_index = 0x40 -+ self.gridline_colour_rgb = None # pre-BIFF8 -+ self.hyperlink_list = [] -+ self.hyperlink_map = {} -+ self.cell_note_map = {} -+ -+ # Values calculated by xlrd to predict the mag factors that -+ # will actually be used by Excel to display your worksheet. -+ # Pass these values to xlwt when writing XLS files. -+ # Warning 1: Behaviour of OOo Calc and Gnumeric has been observed to differ from Excel's. -+ # Warning 2: A value of zero means almost exactly what it says. Your sheet will be -+ # displayed as a very tiny speck on the screen. xlwt will reject attempts to set -+ # a mag_factor that is not (10 <= mag_factor <= 400). -+ self.cooked_page_break_preview_mag_factor = 60 -+ self.cooked_normal_view_mag_factor = 100 -+ -+ # Values (if any) actually stored on the XLS file -+ self.cached_page_break_preview_mag_factor = None # from WINDOW2 record -+ self.cached_normal_view_mag_factor = None # from WINDOW2 record -+ self.scl_mag_factor = None # from SCL record -+ -+ self._ixfe = None # BIFF2 only -+ self._cell_attr_to_xfx = {} # BIFF2.0 only -+ -+ #### Don't initialise this here, use class attribute initialisation. -+ #### self.gcw = (0, ) * 256 #### -+ -+ if self.biff_version >= 80: -+ self.utter_max_rows = 65536 -+ else: -+ self.utter_max_rows = 16384 -+ self.utter_max_cols = 256 -+ -+ self._first_full_rowx = -1 -+ -+ # self._put_cell_exceptions = 0 -+ # self._put_cell_row_widenings = 0 -+ # self._put_cell_rows_appended = 0 -+ # self._put_cell_cells_appended = 0 -+ -+ -+ ## -+ # {@link #Cell} object in the given row and column. -+ def cell(self, rowx, colx): -+ if self.formatting_info: -+ xfx = self.cell_xf_index(rowx, colx) -+ else: -+ xfx = None -+ return Cell( -+ self._cell_types[rowx][colx], -+ self._cell_values[rowx][colx], -+ xfx, -+ ) -+ -+ ## -+ # Value of the cell in the given row and column. -+ def cell_value(self, rowx, colx): -+ return self._cell_values[rowx][colx] -+ -+ ## -+ # Type of the cell in the given row and column. -+ # Refer to the documentation of the {@link #Cell} class. -+ def cell_type(self, rowx, colx): -+ return self._cell_types[rowx][colx] -+ -+ ## -+ # XF index of the cell in the given row and column. -+ # This is an index into Book.{@link #Book.xf_list}. -+ #
-- New in version 0.6.1 -+ def cell_xf_index(self, rowx, colx): -+ self.req_fmt_info() -+ xfx = self._cell_xf_indexes[rowx][colx] -+ if xfx > -1: -+ self._xf_index_stats[0] += 1 -+ return xfx -+ # Check for a row xf_index -+ try: -+ xfx = self.rowinfo_map[rowx].xf_index -+ if xfx > -1: -+ self._xf_index_stats[1] += 1 -+ return xfx -+ except KeyError: -+ pass -+ # Check for a column xf_index -+ try: -+ xfx = self.colinfo_map[colx].xf_index -+ if xfx == -1: xfx = 15 -+ self._xf_index_stats[2] += 1 -+ return xfx -+ except KeyError: -+ # If all else fails, 15 is used as hardwired global default xf_index. -+ self._xf_index_stats[3] += 1 -+ return 15 -+ -+ ## -+ # Returns the effective number of cells in the given row. For use with -+ # open_workbook(ragged_rows=True) which is likely to produce rows -+ # with fewer than {@link #Sheet.ncols} cells. -+ #
-- New in version 0.7.2 -+ def row_len(self, rowx): -+ return len(self._cell_values[rowx]) -+ -+ ## -+ # Returns a sequence of the {@link #Cell} objects in the given row. -+ def row(self, rowx): -+ return [ -+ self.cell(rowx, colx) -+ for colx in xrange(len(self._cell_values[rowx])) -+ ] -+ -+ ## -+ # Returns a slice of the types -+ # of the cells in the given row. -+ def row_types(self, rowx, start_colx=0, end_colx=None): -+ if end_colx is None: -+ return self._cell_types[rowx][start_colx:] -+ return self._cell_types[rowx][start_colx:end_colx] -+ -+ ## -+ # Returns a slice of the values -+ # of the cells in the given row. -+ def row_values(self, rowx, start_colx=0, end_colx=None): -+ if end_colx is None: -+ return self._cell_values[rowx][start_colx:] -+ return self._cell_values[rowx][start_colx:end_colx] -+ -+ ## -+ # Returns a slice of the {@link #Cell} objects in the given row. -+ def row_slice(self, rowx, start_colx=0, end_colx=None): -+ nc = len(self._cell_values[rowx]) -+ if start_colx < 0: -+ start_colx += nc -+ if start_colx < 0: -+ start_colx = 0 -+ if end_colx is None or end_colx > nc: -+ end_colx = nc -+ elif end_colx < 0: -+ end_colx += nc -+ return [ -+ self.cell(rowx, colx) -+ for colx in xrange(start_colx, end_colx) -+ ] -+ -+ ## -+ # Returns a slice of the {@link #Cell} objects in the given column. -+ def col_slice(self, colx, start_rowx=0, end_rowx=None): -+ nr = self.nrows -+ if start_rowx < 0: -+ start_rowx += nr -+ if start_rowx < 0: -+ start_rowx = 0 -+ if end_rowx is None or end_rowx > nr: -+ end_rowx = nr -+ elif end_rowx < 0: -+ end_rowx += nr -+ return [ -+ self.cell(rowx, colx) -+ for rowx in xrange(start_rowx, end_rowx) -+ ] -+ -+ ## -+ # Returns a slice of the values of the cells in the given column. -+ def col_values(self, colx, start_rowx=0, end_rowx=None): -+ nr = self.nrows -+ if start_rowx < 0: -+ start_rowx += nr -+ if start_rowx < 0: -+ start_rowx = 0 -+ if end_rowx is None or end_rowx > nr: -+ end_rowx = nr -+ elif end_rowx < 0: -+ end_rowx += nr -+ return [ -+ self._cell_values[rowx][colx] -+ for rowx in xrange(start_rowx, end_rowx) -+ ] -+ -+ ## -+ # Returns a slice of the types of the cells in the given column. -+ def col_types(self, colx, start_rowx=0, end_rowx=None): -+ nr = self.nrows -+ if start_rowx < 0: -+ start_rowx += nr -+ if start_rowx < 0: -+ start_rowx = 0 -+ if end_rowx is None or end_rowx > nr: -+ end_rowx = nr -+ elif end_rowx < 0: -+ end_rowx += nr -+ return [ -+ self._cell_types[rowx][colx] -+ for rowx in xrange(start_rowx, end_rowx) -+ ] -+ -+ ## -+ # Returns a sequence of the {@link #Cell} objects in the given column. -+ def col(self, colx): -+ return self.col_slice(colx) -+ # Above two lines just for the docs. Here's the real McCoy: -+ col = col_slice -+ -+ # === Following methods are used in building the worksheet. -+ # === They are not part of the API. -+ -+ def tidy_dimensions(self): -+ if self.verbosity >= 3: -+ fprintf(self.logfile, -+ "tidy_dimensions: nrows=%d ncols=%d \n", -+ self.nrows, self.ncols, -+ ) -+ if 1 and self.merged_cells: -+ nr = nc = 0 -+ umaxrows = self.utter_max_rows -+ umaxcols = self.utter_max_cols -+ for crange in self.merged_cells: -+ rlo, rhi, clo, chi = crange -+ if not (0 <= rlo < rhi <= umaxrows) \ -+ or not (0 <= clo < chi <= umaxcols): -+ fprintf(self.logfile, -+ "*** WARNING: sheet #%d (%r), MERGEDCELLS bad range %r\n", -+ self.number, self.name, crange) -+ if rhi > nr: nr = rhi -+ if chi > nc: nc = chi -+ if nc > self.ncols: -+ self.ncols = nc -+ if nr > self.nrows: -+ # we put one empty cell at (nr-1,0) to make sure -+ # we have the right number of rows. The ragged rows -+ # will sort out the rest if needed. -+ self.put_cell(nr-1, 0, XL_CELL_EMPTY, '', -1) -+ if self.verbosity >= 1 \ -+ and (self.nrows != self._dimnrows or self.ncols != self._dimncols): -+ fprintf(self.logfile, -+ "NOTE *** sheet %d (%r): DIMENSIONS R,C = %d,%d should be %d,%d\n", -+ self.number, -+ self.name, -+ self._dimnrows, -+ self._dimncols, -+ self.nrows, -+ self.ncols, -+ ) -+ if not self.ragged_rows: -+ # fix ragged rows -+ ncols = self.ncols -+ s_cell_types = self._cell_types -+ s_cell_values = self._cell_values -+ s_cell_xf_indexes = self._cell_xf_indexes -+ s_fmt_info = self.formatting_info -+ # for rowx in xrange(self.nrows): -+ if self._first_full_rowx == -2: -+ ubound = self.nrows -+ else: -+ ubound = self._first_full_rowx -+ for rowx in xrange(ubound): -+ trow = s_cell_types[rowx] -+ rlen = len(trow) -+ nextra = ncols - rlen -+ if nextra > 0: -+ s_cell_values[rowx][rlen:] = [''] * nextra -+ trow[rlen:] = self.bt * nextra -+ if s_fmt_info: -+ s_cell_xf_indexes[rowx][rlen:] = self.bf * nextra -+ -+ def put_cell_ragged(self, rowx, colx, ctype, value, xf_index): -+ if ctype is None: -+ # we have a number, so look up the cell type -+ ctype = self._xf_index_to_xl_type_map[xf_index] -+ assert 0 <= colx < self.utter_max_cols -+ assert 0 <= rowx < self.utter_max_rows -+ fmt_info = self.formatting_info -+ -+ try: -+ nr = rowx + 1 -+ if self.nrows < nr: -+ -+ scta = self._cell_types.append -+ scva = self._cell_values.append -+ scxa = self._cell_xf_indexes.append -+ bt = self.bt -+ bf = self.bf -+ for _unused in xrange(self.nrows, nr): -+ scta(bt * 0) -+ scva([]) -+ if fmt_info: -+ scxa(bf * 0) -+ self.nrows = nr -+ -+ types_row = self._cell_types[rowx] -+ values_row = self._cell_values[rowx] -+ if fmt_info: -+ fmt_row = self._cell_xf_indexes[rowx] -+ ltr = len(types_row) -+ if colx >= self.ncols: -+ self.ncols = colx + 1 -+ num_empty = colx - ltr -+ if not num_empty: -+ # most common case: colx == previous colx + 1 -+ # self._put_cell_cells_appended += 1 -+ types_row.append(ctype) -+ values_row.append(value) -+ if fmt_info: -+ fmt_row.append(xf_index) -+ return -+ if num_empty > 0: -+ num_empty += 1 -+ # self._put_cell_row_widenings += 1 -+ # types_row.extend(self.bt * num_empty) -+ # values_row.extend([''] * num_empty) -+ # if fmt_info: -+ # fmt_row.extend(self.bf * num_empty) -+ types_row[ltr:] = self.bt * num_empty -+ values_row[ltr:] = [''] * num_empty -+ if fmt_info: -+ fmt_row[ltr:] = self.bf * num_empty -+ types_row[colx] = ctype -+ values_row[colx] = value -+ if fmt_info: -+ fmt_row[colx] = xf_index -+ except: -+ print("put_cell", rowx, colx, file=self.logfile) -+ raise -+ -+ def put_cell_unragged(self, rowx, colx, ctype, value, xf_index): -+ if ctype is None: -+ # we have a number, so look up the cell type -+ ctype = self._xf_index_to_xl_type_map[xf_index] -+ # assert 0 <= colx < self.utter_max_cols -+ # assert 0 <= rowx < self.utter_max_rows -+ try: -+ self._cell_types[rowx][colx] = ctype -+ self._cell_values[rowx][colx] = value -+ if self.formatting_info: -+ self._cell_xf_indexes[rowx][colx] = xf_index -+ except IndexError: -+ # print >> self.logfile, "put_cell extending", rowx, colx -+ # self.extend_cells(rowx+1, colx+1) -+ # self._put_cell_exceptions += 1 -+ nr = rowx + 1 -+ nc = colx + 1 -+ assert 1 <= nc <= self.utter_max_cols -+ assert 1 <= nr <= self.utter_max_rows -+ if nc > self.ncols: -+ self.ncols = nc -+ # The row self._first_full_rowx and all subsequent rows -+ # are guaranteed to have length == self.ncols. Thus the -+ # "fix ragged rows" section of the tidy_dimensions method -+ # doesn't need to examine them. -+ if nr < self.nrows: -+ # cell data is not in non-descending row order *AND* -+ # self.ncols has been bumped up. -+ # This very rare case ruins this optmisation. -+ self._first_full_rowx = -2 -+ elif rowx > self._first_full_rowx > -2: -+ self._first_full_rowx = rowx -+ if nr <= self.nrows: -+ # New cell is in an existing row, so extend that row (if necessary). -+ # Note that nr < self.nrows means that the cell data -+ # is not in ascending row order!! -+ trow = self._cell_types[rowx] -+ nextra = self.ncols - len(trow) -+ if nextra > 0: -+ # self._put_cell_row_widenings += 1 -+ trow.extend(self.bt * nextra) -+ if self.formatting_info: -+ self._cell_xf_indexes[rowx].extend(self.bf * nextra) -+ self._cell_values[rowx].extend([''] * nextra) -+ else: -+ scta = self._cell_types.append -+ scva = self._cell_values.append -+ scxa = self._cell_xf_indexes.append -+ fmt_info = self.formatting_info -+ nc = self.ncols -+ bt = self.bt -+ bf = self.bf -+ for _unused in xrange(self.nrows, nr): -+ # self._put_cell_rows_appended += 1 -+ scta(bt * nc) -+ scva([''] * nc) -+ if fmt_info: -+ scxa(bf * nc) -+ self.nrows = nr -+ # === end of code from extend_cells() -+ try: -+ self._cell_types[rowx][colx] = ctype -+ self._cell_values[rowx][colx] = value -+ if self.formatting_info: -+ self._cell_xf_indexes[rowx][colx] = xf_index -+ except: -+ print("put_cell", rowx, colx, file=self.logfile) -+ raise -+ except: -+ print("put_cell", rowx, colx, file=self.logfile) -+ raise -+ -+ -+ # === Methods after this line neither know nor care about how cells are stored. -+ -+ def read(self, bk): -+ global rc_stats -+ DEBUG = 0 -+ blah = DEBUG or self.verbosity >= 2 -+ blah_rows = DEBUG or self.verbosity >= 4 -+ blah_formulas = 0 and blah -+ r1c1 = 0 -+ oldpos = bk._position -+ bk._position = self._position -+ XL_SHRFMLA_ETC_ETC = ( -+ XL_SHRFMLA, XL_ARRAY, XL_TABLEOP, XL_TABLEOP2, -+ XL_ARRAY2, XL_TABLEOP_B2, -+ ) -+ self_put_cell = self.put_cell -+ local_unpack = unpack -+ bk_get_record_parts = bk.get_record_parts -+ bv = self.biff_version -+ fmt_info = self.formatting_info -+ do_sst_rich_text = fmt_info and bk._rich_text_runlist_map -+ rowinfo_sharing_dict = {} -+ txos = {} -+ eof_found = 0 -+ while 1: -+ # if DEBUG: print "SHEET.READ: about to read from position %d" % bk._position -+ rc, data_len, data = bk_get_record_parts() -+ # if rc in rc_stats: -+ # rc_stats[rc] += 1 -+ # else: -+ # rc_stats[rc] = 1 -+ # if DEBUG: print "SHEET.READ: op 0x%04x, %d bytes %r" % (rc, data_len, data) -+ if rc == XL_NUMBER: -+ # [:14] in following stmt ignores extraneous rubbish at end of record. -+ # Sample file testEON-8.xls supplied by Jan Kraus. -+ rowx, colx, xf_index, d = local_unpack('> 15) & 1 -+ r.outline_level = bits2 & 7 -+ r.outline_group_starts_ends = (bits2 >> 4) & 1 -+ r.hidden = (bits2 >> 5) & 1 -+ r.height_mismatch = (bits2 >> 6) & 1 -+ r.has_default_xf_index = (bits2 >> 7) & 1 -+ r.xf_index = (bits2 >> 16) & 0xfff -+ r.additional_space_above = (bits2 >> 28) & 1 -+ r.additional_space_below = (bits2 >> 29) & 1 -+ if not r.has_default_xf_index: -+ r.xf_index = -1 -+ self.rowinfo_map[rowx] = r -+ if 0 and r.xf_index > -1: -+ fprintf(self.logfile, -+ "**ROW %d %d %d\n", -+ self.number, rowx, r.xf_index) -+ if blah_rows: -+ print('ROW', rowx, bits1, bits2, file=self.logfile) -+ r.dump(self.logfile, -+ header="--- sh #%d, rowx=%d ---" % (self.number, rowx)) -+ elif rc in XL_FORMULA_OPCODES: # 06, 0206, 0406 -+ # DEBUG = 1 -+ # if DEBUG: print "FORMULA: rc: 0x%04x data: %r" % (rc, data) -+ if bv >= 50: -+ rowx, colx, xf_index, result_str, flags = local_unpack('= 30: -+ rowx, colx, xf_index, result_str, flags = local_unpack(' 255: break # Excel does 0 to 256 inclusive -+ self.colinfo_map[colx] = c -+ if 0: -+ fprintf(self.logfile, -+ "**COL %d %d %d\n", -+ self.number, colx, c.xf_index) -+ if blah: -+ fprintf( -+ self.logfile, -+ "COLINFO sheet #%d cols %d-%d: wid=%d xf_index=%d flags=0x%04x\n", -+ self.number, first_colx, last_colx, c.width, c.xf_index, flags, -+ ) -+ c.dump(self.logfile, header='===') -+ elif rc == XL_DEFCOLWIDTH: -+ self.defcolwidth, = local_unpack(">= 1 -+ self.gcw = tuple(gcw) -+ if 0: -+ showgcw = "".join(map(lambda x: "F "[x], gcw)).rstrip().replace(' ', '.') -+ print("GCW:", showgcw, file=self.logfile) -+ elif rc == XL_BLANK: -+ if not fmt_info: continue -+ rowx, colx, xf_index = local_unpack('> self.logfile, "BLANK", rowx, colx, xf_index -+ self_put_cell(rowx, colx, XL_CELL_BLANK, '', xf_index) -+ elif rc == XL_MULBLANK: # 00BE -+ if not fmt_info: continue -+ nitems = data_len >> 1 -+ result = local_unpack("<%dH" % nitems, data) -+ rowx, mul_first = result[:2] -+ mul_last = result[-1] -+ # print >> self.logfile, "MULBLANK", rowx, mul_first, mul_last, data_len, nitems, mul_last + 4 - mul_first -+ assert nitems == mul_last + 4 - mul_first -+ pos = 2 -+ for colx in xrange(mul_first, mul_last + 1): -+ self_put_cell(rowx, colx, XL_CELL_BLANK, '', result[pos]) -+ pos += 1 -+ elif rc == XL_DIMENSION or rc == XL_DIMENSION2: -+ if data_len == 0: -+ # Four zero bytes after some other record. See github issue 64. -+ continue -+ # if data_len == 10: -+ # Was crashing on BIFF 4.0 file w/o the two trailing unused bytes. -+ # Reported by Ralph Heimburger. -+ if bv < 80: -+ dim_tuple = local_unpack(' found EOF", file=self.logfile) -+ elif rc == XL_COUNTRY: -+ bk.handle_country(data) -+ elif rc == XL_LABELRANGES: -+ pos = 0 -+ pos = unpack_cell_range_address_list_update_pos( -+ self.row_label_ranges, data, pos, bv, addr_size=8, -+ ) -+ pos = unpack_cell_range_address_list_update_pos( -+ self.col_label_ranges, data, pos, bv, addr_size=8, -+ ) -+ assert pos == data_len -+ elif rc == XL_ARRAY: -+ row1x, rownx, col1x, colnx, array_flags, tokslen = \ -+ local_unpack("= 80 -+ num_CFs, needs_recalc, browx1, browx2, bcolx1, bcolx2 = \ -+ unpack("<6H", data[0:12]) -+ if self.verbosity >= 1: -+ fprintf(self.logfile, -+ "\n*** WARNING: Ignoring CONDFMT (conditional formatting) record\n" \ -+ "*** in Sheet %d (%r).\n" \ -+ "*** %d CF record(s); needs_recalc_or_redraw = %d\n" \ -+ "*** Bounding box is %s\n", -+ self.number, self.name, num_CFs, needs_recalc, -+ rangename2d(browx1, browx2+1, bcolx1, bcolx2+1), -+ ) -+ olist = [] # updated by the function -+ pos = unpack_cell_range_address_list_update_pos( -+ olist, data, 12, bv, addr_size=8) -+ # print >> self.logfile, repr(result), len(result) -+ if self.verbosity >= 1: -+ fprintf(self.logfile, -+ "*** %d individual range(s):\n" \ -+ "*** %s\n", -+ len(olist), -+ ", ".join([rangename2d(*coords) for coords in olist]), -+ ) -+ elif rc == XL_CF: -+ if not fmt_info: continue -+ cf_type, cmp_op, sz1, sz2, flags = unpack("> 26) & 1 -+ bord_block = (flags >> 28) & 1 -+ patt_block = (flags >> 29) & 1 -+ if self.verbosity >= 1: -+ fprintf(self.logfile, -+ "\n*** WARNING: Ignoring CF (conditional formatting) sub-record.\n" \ -+ "*** cf_type=%d, cmp_op=%d, sz1=%d, sz2=%d, flags=0x%08x\n" \ -+ "*** optional data blocks: font=%d, border=%d, pattern=%d\n", -+ cf_type, cmp_op, sz1, sz2, flags, -+ font_block, bord_block, patt_block, -+ ) -+ # hex_char_dump(data, 0, data_len, fout=self.logfile) -+ pos = 12 -+ if font_block: -+ (font_height, font_options, weight, escapement, underline, -+ font_colour_index, two_bits, font_esc, font_underl) = \ -+ unpack("<64x i i H H B 3x i 4x i i i 18x", data[pos:pos+118]) -+ font_style = (two_bits > 1) & 1 -+ posture = (font_options > 1) & 1 -+ font_canc = (two_bits > 7) & 1 -+ cancellation = (font_options > 7) & 1 -+ if self.verbosity >= 1: -+ fprintf(self.logfile, -+ "*** Font info: height=%d, weight=%d, escapement=%d,\n" \ -+ "*** underline=%d, colour_index=%d, esc=%d, underl=%d,\n" \ -+ "*** style=%d, posture=%d, canc=%d, cancellation=%d\n", -+ font_height, weight, escapement, underline, -+ font_colour_index, font_esc, font_underl, -+ font_style, posture, font_canc, cancellation, -+ ) -+ pos += 118 -+ if bord_block: -+ pos += 8 -+ if patt_block: -+ pos += 4 -+ fmla1 = data[pos:pos+sz1] -+ pos += sz1 -+ if blah and sz1: -+ fprintf(self.logfile, -+ "*** formula 1:\n", -+ ) -+ dump_formula(bk, fmla1, sz1, bv, reldelta=0, blah=1) -+ fmla2 = data[pos:pos+sz2] -+ pos += sz2 -+ assert pos == data_len -+ if blah and sz2: -+ fprintf(self.logfile, -+ "*** formula 2:\n", -+ ) -+ dump_formula(bk, fmla2, sz2, bv, reldelta=0, blah=1) -+ elif rc == XL_DEFAULTROWHEIGHT: -+ if data_len == 4: -+ bits, self.default_row_height = unpack("> 1) & 1 -+ self.default_additional_space_above = (bits >> 2) & 1 -+ self.default_additional_space_below = (bits >> 3) & 1 -+ elif rc == XL_MERGEDCELLS: -+ if not fmt_info: continue -+ pos = unpack_cell_range_address_list_update_pos( -+ self.merged_cells, data, 0, bv, addr_size=8) -+ if blah: -+ fprintf(self.logfile, -+ "MERGEDCELLS: %d ranges\n", (pos - 2) // 8) -+ assert pos == data_len, \ -+ "MERGEDCELLS: pos=%d data_len=%d" % (pos, data_len) -+ elif rc == XL_WINDOW2: -+ if bv >= 80 and data_len >= 14: -+ (options, -+ self.first_visible_rowx, self.first_visible_colx, -+ self.gridline_colour_index, -+ self.cached_page_break_preview_mag_factor, -+ self.cached_normal_view_mag_factor -+ ) = unpack("= 30 # BIFF3-7 -+ (options, -+ self.first_visible_rowx, self.first_visible_colx, -+ ) = unpack(">= 1 -+ elif rc == XL_SCL: -+ num, den = unpack("= 0: -+ print(( -+ "WARNING *** SCL rcd sheet %d: should have 0.1 <= num/den <= 4; got %d/%d" -+ % (self.number, num, den) -+ ), file=self.logfile) -+ result = 100 -+ self.scl_mag_factor = result -+ elif rc == XL_PANE: -+ ( -+ self.vert_split_pos, -+ self.horz_split_pos, -+ self.horz_split_first_visible, -+ self.vert_split_first_visible, -+ self.split_active_pane, -+ ) = unpack("= 80)) + 2 == data_len -+ pos = 2 -+ if bv < 80: -+ while pos < data_len: -+ self.horizontal_page_breaks.append((local_unpack("= 80)) + 2 == data_len -+ pos = 2 -+ if bv < 80: -+ while pos < data_len: -+ self.vertical_page_breaks.append((local_unpack("> 15) & 1 -+ r.has_default_xf_index = bits2 & 1 -+ r.xf_index = xf_index -+ # r.outline_level = 0 # set in __init__ -+ # r.outline_group_starts_ends = 0 # set in __init__ -+ # r.hidden = 0 # set in __init__ -+ # r.height_mismatch = 0 # set in __init__ -+ # r.additional_space_above = 0 # set in __init__ -+ # r.additional_space_below = 0 # set in __init__ -+ self.rowinfo_map[rowx] = r -+ if 0 and r.xf_index > -1: -+ fprintf(self.logfile, -+ "**ROW %d %d %d\n", -+ self.number, rowx, r.xf_index) -+ if blah_rows: -+ print('ROW_B2', rowx, bits1, has_defaults, file=self.logfile) -+ r.dump(self.logfile, -+ header="--- sh #%d, rowx=%d ---" % (self.number, rowx)) -+ elif rc == XL_COLWIDTH: # BIFF2 only -+ if not fmt_info: continue -+ first_colx, last_colx, width\ -+ = local_unpack("= 30) + 1 -+ nchars_expected = unpack("<" + "BH"[lenlen - 1], data[:lenlen])[0] -+ offset = lenlen -+ if bv < 80: -+ enc = bk.encoding or bk.derive_encoding() -+ nchars_found = 0 -+ result = UNICODE_LITERAL("") -+ while 1: -+ if bv >= 80: -+ flag = BYTES_ORD(data[offset]) & 1 -+ enc = ("latin_1", "utf_16_le")[flag] -+ offset += 1 -+ chunk = unicode(data[offset:], enc) -+ result += chunk -+ nchars_found += len(chunk) -+ if nchars_found == nchars_expected: -+ return result -+ if nchars_found > nchars_expected: -+ msg = ("STRING/CONTINUE: expected %d chars, found %d" -+ % (nchars_expected, nchars_found)) -+ raise XLRDError(msg) -+ rc, _unused_len, data = bk.get_record_parts() -+ if rc != XL_CONTINUE: -+ raise XLRDError( -+ "Expected CONTINUE record; found record-type 0x%04X" % rc) -+ offset = 0 -+ -+ def update_cooked_mag_factors(self): -+ # Cached values are used ONLY for the non-active view mode. -+ # When the user switches to the non-active view mode, -+ # if the cached value for that mode is not valid, -+ # Excel pops up a window which says: -+ # "The number must be between 10 and 400. Try again by entering a number in this range." -+ # When the user hits OK, it drops into the non-active view mode -+ # but uses the magn from the active mode. -+ # NOTE: definition of "valid" depends on mode ... see below -+ blah = DEBUG or self.verbosity > 0 -+ if self.show_in_page_break_preview: -+ if self.scl_mag_factor is None: # no SCL record -+ self.cooked_page_break_preview_mag_factor = 100 # Yes, 100, not 60, NOT a typo -+ else: -+ self.cooked_page_break_preview_mag_factor = self.scl_mag_factor -+ zoom = self.cached_normal_view_mag_factor -+ if not (10 <= zoom <=400): -+ if blah: -+ print(( -+ "WARNING *** WINDOW2 rcd sheet %d: Bad cached_normal_view_mag_factor: %d" -+ % (self.number, self.cached_normal_view_mag_factor) -+ ), file=self.logfile) -+ zoom = self.cooked_page_break_preview_mag_factor -+ self.cooked_normal_view_mag_factor = zoom -+ else: -+ # normal view mode -+ if self.scl_mag_factor is None: # no SCL record -+ self.cooked_normal_view_mag_factor = 100 -+ else: -+ self.cooked_normal_view_mag_factor = self.scl_mag_factor -+ zoom = self.cached_page_break_preview_mag_factor -+ if zoom == 0: -+ # VALID, defaults to 60 -+ zoom = 60 -+ elif not (10 <= zoom <= 400): -+ if blah: -+ print(( -+ "WARNING *** WINDOW2 rcd sheet %r: Bad cached_page_break_preview_mag_factor: %r" -+ % (self.number, self.cached_page_break_preview_mag_factor) -+ ), file=self.logfile) -+ zoom = self.cooked_normal_view_mag_factor -+ self.cooked_page_break_preview_mag_factor = zoom -+ -+ def fixed_BIFF2_xfindex(self, cell_attr, rowx, colx, true_xfx=None): -+ DEBUG = 0 -+ blah = DEBUG or self.verbosity >= 2 -+ if self.biff_version == 21: -+ if self.book.xf_list: -+ if true_xfx is not None: -+ xfx = true_xfx -+ else: -+ xfx = BYTES_ORD(cell_attr[0]) & 0x3F -+ if xfx == 0x3F: -+ if self._ixfe is None: -+ raise XLRDError("BIFF2 cell record has XF index 63 but no preceding IXFE record.") -+ xfx = self._ixfe -+ # OOo docs are capable of interpretation that each -+ # cell record is preceded immediately by its own IXFE record. -+ # Empirical evidence is that (sensibly) an IXFE record applies to all -+ # following cell records until another IXFE comes along. -+ return xfx -+ # Have either Excel 2.0, or broken 2.1 w/o XF records -- same effect. -+ self.biff_version = self.book.biff_version = 20 -+ #### check that XF slot in cell_attr is zero -+ xfx_slot = BYTES_ORD(cell_attr[0]) & 0x3F -+ assert xfx_slot == 0 -+ xfx = self._cell_attr_to_xfx.get(cell_attr) -+ if xfx is not None: -+ return xfx -+ if blah: -+ fprintf(self.logfile, "New cell_attr %r at (%r, %r)\n", cell_attr, rowx, colx) -+ if not self.book.xf_list: -+ for xfx in xrange(16): -+ self.insert_new_BIFF20_xf(cell_attr=b"\x40\x00\x00", style=xfx < 15) -+ xfx = self.insert_new_BIFF20_xf(cell_attr=cell_attr) -+ return xfx -+ -+ def insert_new_BIFF20_xf(self, cell_attr, style=0): -+ DEBUG = 0 -+ blah = DEBUG or self.verbosity >= 2 -+ book = self.book -+ xfx = len(book.xf_list) -+ xf = self.fake_XF_from_BIFF20_cell_attr(cell_attr, style) -+ xf.xf_index = xfx -+ book.xf_list.append(xf) -+ if blah: -+ xf.dump(self.logfile, header="=== Faked XF %d ===" % xfx, footer="======") -+ if xf.format_key not in book.format_map: -+ if xf.format_key: -+ msg = "ERROR *** XF[%d] unknown format key (%d, 0x%04x)\n" -+ fprintf(self.logfile, msg, -+ xf.xf_index, xf.format_key, xf.format_key) -+ fmt = Format(xf.format_key, FUN, UNICODE_LITERAL("General")) -+ book.format_map[xf.format_key] = fmt -+ book.format_list.append(fmt) -+ cellty_from_fmtty = { -+ FNU: XL_CELL_NUMBER, -+ FUN: XL_CELL_NUMBER, -+ FGE: XL_CELL_NUMBER, -+ FDT: XL_CELL_DATE, -+ FTX: XL_CELL_NUMBER, # Yes, a number can be formatted as text. -+ } -+ fmt = book.format_map[xf.format_key] -+ cellty = cellty_from_fmtty[fmt.type] -+ self._xf_index_to_xl_type_map[xf.xf_index] = cellty -+ self._cell_attr_to_xfx[cell_attr] = xfx -+ return xfx -+ -+ def fake_XF_from_BIFF20_cell_attr(self, cell_attr, style=0): -+ from .formatting import XF, XFAlignment, XFBorder, XFBackground, XFProtection -+ xf = XF() -+ xf.alignment = XFAlignment() -+ xf.alignment.indent_level = 0 -+ xf.alignment.shrink_to_fit = 0 -+ xf.alignment.text_direction = 0 -+ xf.border = XFBorder() -+ xf.border.diag_up = 0 -+ xf.border.diag_down = 0 -+ xf.border.diag_colour_index = 0 -+ xf.border.diag_line_style = 0 # no line -+ xf.background = XFBackground() -+ xf.protection = XFProtection() -+ (prot_bits, font_and_format, halign_etc) = unpack('> 6 -+ upkbits(xf.protection, prot_bits, ( -+ (6, 0x40, 'cell_locked'), -+ (7, 0x80, 'formula_hidden'), -+ )) -+ xf.alignment.hor_align = halign_etc & 0x07 -+ for mask, side in ((0x08, 'left'), (0x10, 'right'), (0x20, 'top'), (0x40, 'bottom')): -+ if halign_etc & mask: -+ colour_index, line_style = 8, 1 # black, thin -+ else: -+ colour_index, line_style = 0, 0 # none, none -+ setattr(xf.border, side + '_colour_index', colour_index) -+ setattr(xf.border, side + '_line_style', line_style) -+ bg = xf.background -+ if halign_etc & 0x80: -+ bg.fill_pattern = 17 -+ else: -+ bg.fill_pattern = 0 -+ bg.background_colour_index = 9 # white -+ bg.pattern_colour_index = 8 # black -+ xf.parent_style_index = (0x0FFF, 0)[style] -+ xf.alignment.vert_align = 2 # bottom -+ xf.alignment.rotation = 0 -+ for attr_stem in \ -+ "format font alignment border background protection".split(): -+ attr = "_" + attr_stem + "_flag" -+ setattr(xf, attr, 1) -+ return xf -+ -+ def req_fmt_info(self): -+ if not self.formatting_info: -+ raise XLRDError("Feature requires open_workbook(..., formatting_info=True)") -+ -+ ## -+ # Determine column display width. -+ #
-- New in version 0.6.1 -+ #
-+ # @param colx Index of the queried column, range 0 to 255. -+ # Note that it is possible to find out the width that will be used to display -+ # columns with no cell information e.g. column IV (colx=255). -+ # @return The column width that will be used for displaying -+ # the given column by Excel, in units of 1/256th of the width of a -+ # standard character (the digit zero in the first font). -+ -+ def computed_column_width(self, colx): -+ self.req_fmt_info() -+ if self.biff_version >= 80: -+ colinfo = self.colinfo_map.get(colx, None) -+ if colinfo is not None: -+ return colinfo.width -+ if self.standardwidth is not None: -+ return self.standardwidth -+ elif self.biff_version >= 40: -+ if self.gcw[colx]: -+ if self.standardwidth is not None: -+ return self.standardwidth -+ else: -+ colinfo = self.colinfo_map.get(colx, None) -+ if colinfo is not None: -+ return colinfo.width -+ elif self.biff_version == 30: -+ colinfo = self.colinfo_map.get(colx, None) -+ if colinfo is not None: -+ return colinfo.width -+ # All roads lead to Rome and the DEFCOLWIDTH ... -+ if self.defcolwidth is not None: -+ return self.defcolwidth * 256 -+ return 8 * 256 # 8 is what Excel puts in a DEFCOLWIDTH record -+ -+ def handle_hlink(self, data): -+ # DEBUG = 1 -+ if DEBUG: print("\n=== hyperlink ===", file=self.logfile) -+ record_size = len(data) -+ h = Hyperlink() -+ h.frowx, h.lrowx, h.fcolx, h.lcolx, guid0, dummy, options = unpack(' 0: -+ fprintf( -+ self.logfile, -+ "*** WARNING: hyperlink at r=%d c=%d has %d extra data bytes: %s\n", -+ h.frowx, -+ h.fcolx, -+ extra_nbytes, -+ REPR(data[-extra_nbytes:]) -+ ) -+ # Seen: b"\x00\x00" also b"A\x00", b"V\x00" -+ elif extra_nbytes < 0: -+ raise XLRDError("Bug or corrupt file, send copy of input file for debugging") -+ -+ self.hyperlink_list.append(h) -+ for rowx in xrange(h.frowx, h.lrowx+1): -+ for colx in xrange(h.fcolx, h.lcolx+1): -+ self.hyperlink_map[rowx, colx] = h -+ -+ def handle_quicktip(self, data): -+ rcx, frowx, lrowx, fcolx, lcolx = unpack('<5H', data[:10]) -+ assert rcx == XL_QUICKTIP -+ assert self.hyperlink_list -+ h = self.hyperlink_list[-1] -+ assert (frowx, lrowx, fcolx, lcolx) == (h.frowx, h.lrowx, h.fcolx, h.lcolx) -+ assert data[-2:] == b'\x00\x00' -+ h.quicktip = unicode(data[10:-2], 'utf_16_le') -+ -+ def handle_msodrawingetc(self, recid, data_len, data): -+ if not OBJ_MSO_DEBUG: -+ return -+ DEBUG = 1 -+ if self.biff_version < 80: -+ return -+ o = MSODrawing() -+ pos = 0 -+ while pos < data_len: -+ tmp, fbt, cb = unpack('> 4) & 0xFFF -+ if ver == 0xF: -+ ndb = 0 # container -+ else: -+ ndb = cb -+ if DEBUG: -+ hex_char_dump(data, pos, ndb + 8, base=0, fout=self.logfile) -+ fprintf(self.logfile, -+ "fbt:0x%04X inst:%d ver:0x%X cb:%d (0x%04X)\n", -+ fbt, inst, ver, cb, cb) -+ if fbt == 0xF010: # Client Anchor -+ assert ndb == 18 -+ (o.anchor_unk, -+ o.anchor_colx_lo, o.anchor_rowx_lo, -+ o.anchor_colx_hi, o.anchor_rowx_hi) = unpack(' 0: -+ rc2, data2_len, data2 = self.book.get_record_parts() -+ assert rc2 == XL_NOTE -+ dummy_rowx, nb = unpack('> 1) & 1 -+ o.row_hidden = (option_flags >> 7) & 1 -+ o.col_hidden = (option_flags >> 8) & 1 -+ # XL97 dev kit book says NULL [sic] bytes padding between string count and string data -+ # to ensure that string is word-aligned. Appears to be nonsense. -+ o.author, endpos = unpack_unicode_update_pos(data, 8, lenlen=2) -+ # There is a random/undefined byte after the author string (not counted in the -+ # string length). -+ # Issue 4 on github: Google Spreadsheet doesn't write the undefined byte. -+ assert (data_len - endpos) in (0, 1) -+ if OBJ_MSO_DEBUG: -+ o.dump(self.logfile, header="=== Note ===", footer= " ") -+ txo = txos.get(o._object_id) -+ if txo: -+ o.text = txo.text -+ o.rich_text_runlist = txo.rich_text_runlist -+ self.cell_note_map[o.rowx, o.colx] = o -+ -+ def handle_txo(self, data): -+ if self.biff_version < 80: -+ return -+ o = MSTxo() -+ data_len = len(data) -+ fmt = ' Represents a user "comment" or "note". -+# Note objects are accessible through Sheet.{@link #Sheet.cell_note_map}. -+#
-- New in version 0.7.2 -+#

-+class Note(BaseObject): -+ ## -+ # Author of note -+ author = UNICODE_LITERAL('') -+ ## -+ # True if the containing column is hidden -+ col_hidden = 0 -+ ## -+ # Column index -+ colx = 0 -+ ## -+ # List of (offset_in_string, font_index) tuples. -+ # Unlike Sheet.{@link #Sheet.rich_text_runlist_map}, the first offset should always be 0. -+ rich_text_runlist = None -+ ## -+ # True if the containing row is hidden -+ row_hidden = 0 -+ ## -+ # Row index -+ rowx = 0 -+ ## -+ # True if note is always shown -+ show = 0 -+ ## -+ # Text of the note -+ text = UNICODE_LITERAL('') -+ -+## -+#

Contains the attributes of a hyperlink. -+# Hyperlink objects are accessible through Sheet.{@link #Sheet.hyperlink_list} -+# and Sheet.{@link #Sheet.hyperlink_map}. -+#
-- New in version 0.7.2 -+#

-+class Hyperlink(BaseObject): -+ ## -+ # Index of first row -+ frowx = None -+ ## -+ # Index of last row -+ lrowx = None -+ ## -+ # Index of first column -+ fcolx = None -+ ## -+ # Index of last column -+ lcolx = None -+ ## -+ # Type of hyperlink. Unicode string, one of 'url', 'unc', -+ # 'local file', 'workbook', 'unknown' -+ type = None -+ ## -+ # The URL or file-path, depending in the type. Unicode string, except -+ # in the rare case of a local but non-existent file with non-ASCII -+ # characters in the name, in which case only the "8.3" filename is available, -+ # as a bytes (3.x) or str (2.x) string, with unknown encoding. -+ url_or_path = None -+ ## -+ # Description ... this is displayed in the cell, -+ # and should be identical to the cell value. Unicode string, or None. It seems -+ # impossible NOT to have a description created by the Excel UI. -+ desc = None -+ ## -+ # Target frame. Unicode string. Note: I have not seen a case of this. -+ # It seems impossible to create one in the Excel UI. -+ target = None -+ ## -+ # "Textmark": the piece after the "#" in -+ # "http://docs.python.org/library#struct_module", or the Sheet1!A1:Z99 -+ # part when type is "workbook". -+ textmark = None -+ ## -+ # The text of the "quick tip" displayed when the cursor -+ # hovers over the hyperlink. -+ quicktip = None -+ -+# === helpers === -+ -+def unpack_RK(rk_str): -+ flags = BYTES_ORD(rk_str[0]) -+ if flags & 2: -+ # There's a SIGNED 30-bit integer in there! -+ i, = unpack('>= 2 # div by 4 to drop the 2 flag bits -+ if flags & 1: -+ return i / 100.0 -+ return float(i) -+ else: -+ # It's the most significant 30 bits of an IEEE 754 64-bit FP number -+ d, = unpack('Contains the data for one cell.

-+# -+#

WARNING: You don't call this class yourself. You access Cell objects -+# via methods of the {@link #Sheet} object(s) that you found in the {@link #Book} object that -+# was returned when you called xlrd.open_workbook("myfile.xls").

-+#

Cell objects have three attributes: ctype is an int, value -+# (which depends on ctype) and xf_index. -+# If "formatting_info" is not enabled when the workbook is opened, xf_index will be None. -+# The following table describes the types of cells and how their values -+# are represented in Python.

-+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+# -+#
Type symbolType numberPython value
XL_CELL_EMPTY0empty string u''
XL_CELL_TEXT1a Unicode string
XL_CELL_NUMBER2float
XL_CELL_DATE3float
XL_CELL_BOOLEAN4int; 1 means TRUE, 0 means FALSE
XL_CELL_ERROR5int representing internal Excel codes; for a text representation, -+# refer to the supplied dictionary error_text_from_code
XL_CELL_BLANK6empty string u''. Note: this type will appear only when -+# open_workbook(..., formatting_info=True) is used.
-+#

-+ -+class Cell(BaseObject): -+ -+ __slots__ = ['ctype', 'value', 'xf_index'] -+ -+ def __init__(self, ctype, value, xf_index=None): -+ self.ctype = ctype -+ self.value = value -+ self.xf_index = xf_index -+ -+ def __repr__(self): -+ if self.xf_index is None: -+ return "%s:%r" % (ctype_text[self.ctype], self.value) -+ else: -+ return "%s:%r (XF:%r)" % (ctype_text[self.ctype], self.value, self.xf_index) -+ -+## -+# There is one and only one instance of an empty cell -- it's a singleton. This is it. -+# You may use a test like "acell is empty_cell". -+empty_cell = Cell(XL_CELL_EMPTY, '') -+ -+##### =============== Colinfo and Rowinfo ============================== ##### -+ -+## -+# Width and default formatting information that applies to one or -+# more columns in a sheet. Derived from COLINFO records. -+# -+#

Here is the default hierarchy for width, according to the OOo docs: -+# -+#
"""In BIFF3, if a COLINFO record is missing for a column, -+# the width specified in the record DEFCOLWIDTH is used instead. -+# -+#
In BIFF4-BIFF7, the width set in this [COLINFO] record is only used, -+# if the corresponding bit for this column is cleared in the GCW -+# record, otherwise the column width set in the DEFCOLWIDTH record -+# is used (the STANDARDWIDTH record is always ignored in this case [see footnote!]). -+# -+#
In BIFF8, if a COLINFO record is missing for a column, -+# the width specified in the record STANDARDWIDTH is used. -+# If this [STANDARDWIDTH] record is also missing, -+# the column width of the record DEFCOLWIDTH is used instead.""" -+#
-+# -+# Footnote: The docs on the GCW record say this: -+# """
-+# If a bit is set, the corresponding column uses the width set in the STANDARDWIDTH -+# record. If a bit is cleared, the corresponding column uses the width set in the -+# COLINFO record for this column. -+#
If a bit is set, and the worksheet does not contain the STANDARDWIDTH record, or if -+# the bit is cleared, and the worksheet does not contain the COLINFO record, the DEFCOLWIDTH -+# record of the worksheet will be used instead. -+#
"""
-+# At the moment (2007-01-17) xlrd is going with the GCW version of the story. -+# Reference to the source may be useful: see the computed_column_width(colx) method -+# of the Sheet class. -+#
-- New in version 0.6.1 -+#

-+ -+class Colinfo(BaseObject): -+ ## -+ # Width of the column in 1/256 of the width of the zero character, -+ # using default font (first FONT record in the file). -+ width = 0 -+ ## -+ # XF index to be used for formatting empty cells. -+ xf_index = -1 -+ ## -+ # 1 = column is hidden -+ hidden = 0 -+ ## -+ # Value of a 1-bit flag whose purpose is unknown -+ # but is often seen set to 1 -+ bit1_flag = 0 -+ ## -+ # Outline level of the column, in range(7). -+ # (0 = no outline) -+ outline_level = 0 -+ ## -+ # 1 = column is collapsed -+ collapsed = 0 -+ -+_USE_SLOTS = 1 -+ -+## -+#

Height and default formatting information that applies to a row in a sheet. -+# Derived from ROW records. -+#
-- New in version 0.6.1

-+# -+#

height: Height of the row, in twips. One twip == 1/20 of a point.

-+# -+#

has_default_height: 0 = Row has custom height; 1 = Row has default height.

-+# -+#

outline_level: Outline level of the row (0 to 7)

-+# -+#

outline_group_starts_ends: 1 = Outline group starts or ends here (depending on where the -+# outline buttons are located, see WSBOOL record [TODO ??]), -+# and is collapsed

-+# -+#

hidden: 1 = Row is hidden (manually, or by a filter or outline group)

-+# -+#

height_mismatch: 1 = Row height and default font height do not match

-+# -+#

has_default_xf_index: 1 = the xf_index attribute is usable; 0 = ignore it

-+# -+#

xf_index: Index to default XF record for empty cells in this row. -+# Don't use this if has_default_xf_index == 0.

-+# -+#

additional_space_above: This flag is set, if the upper border of at least one cell in this row -+# or if the lower border of at least one cell in the row above is -+# formatted with a thick line style. Thin and medium line styles are not -+# taken into account.

-+# -+#

additional_space_below: This flag is set, if the lower border of at least one cell in this row -+# or if the upper border of at least one cell in the row below is -+# formatted with a medium or thick line style. Thin line styles are not -+# taken into account.

-+ -+class Rowinfo(BaseObject): -+ -+ if _USE_SLOTS: -+ __slots__ = ( -+ "height", -+ "has_default_height", -+ "outline_level", -+ "outline_group_starts_ends", -+ "hidden", -+ "height_mismatch", -+ "has_default_xf_index", -+ "xf_index", -+ "additional_space_above", -+ "additional_space_below", -+ ) -+ -+ def __init__(self): -+ self.height = None -+ self.has_default_height = None -+ self.outline_level = None -+ self.outline_group_starts_ends = None -+ self.hidden = None -+ self.height_mismatch = None -+ self.has_default_xf_index = None -+ self.xf_index = None -+ self.additional_space_above = None -+ self.additional_space_below = None -+ -+ def __getstate__(self): -+ return ( -+ self.height, -+ self.has_default_height, -+ self.outline_level, -+ self.outline_group_starts_ends, -+ self.hidden, -+ self.height_mismatch, -+ self.has_default_xf_index, -+ self.xf_index, -+ self.additional_space_above, -+ self.additional_space_below, -+ ) -+ -+ def __setstate__(self, state): -+ ( -+ self.height, -+ self.has_default_height, -+ self.outline_level, -+ self.outline_group_starts_ends, -+ self.hidden, -+ self.height_mismatch, -+ self.has_default_xf_index, -+ self.xf_index, -+ self.additional_space_above, -+ self.additional_space_below, -+ ) = state -diff --git a/webhub/xlrd/sheet.pyc b/webhub/xlrd/sheet.pyc -new file mode 100644 -index 0000000..951a500 -Binary files /dev/null and b/webhub/xlrd/sheet.pyc differ -diff --git a/webhub/xlrd/timemachine.py b/webhub/xlrd/timemachine.py -new file mode 100644 -index 0000000..a068db3 ---- /dev/null -+++ b/webhub/xlrd/timemachine.py -@@ -0,0 +1,52 @@ -+## -+#

Copyright (c) 2006-2012 Stephen John Machin, Lingfo Pty Ltd

-+#

This module is part of the xlrd package, which is released under a BSD-style licence.

-+## -+ -+# timemachine.py -- adaptation for single codebase. -+# Currently supported: 2.6 to 2.7, 3.2+ -+# usage: from timemachine import * -+ -+from __future__ import print_function -+import sys -+ -+python_version = sys.version_info[:2] # e.g. version 2.6 -> (2, 6) -+ -+if python_version >= (3, 0): -+ # Python 3 -+ BYTES_LITERAL = lambda x: x.encode('latin1') -+ UNICODE_LITERAL = lambda x: x -+ BYTES_ORD = lambda byte: byte -+ from io import BytesIO as BYTES_IO -+ def fprintf(f, fmt, *vargs): -+ fmt = fmt.replace("%r", "%a") -+ if fmt.endswith('\n'): -+ print(fmt[:-1] % vargs, file=f) -+ else: -+ print(fmt % vargs, end=' ', file=f) -+ EXCEL_TEXT_TYPES = (str, bytes, bytearray) # xlwt: isinstance(obj, EXCEL_TEXT_TYPES) -+ REPR = ascii -+ xrange = range -+ unicode = lambda b, enc: b.decode(enc) -+ ensure_unicode = lambda s: s -+ unichr = chr -+else: -+ # Python 2 -+ BYTES_LITERAL = lambda x: x -+ UNICODE_LITERAL = lambda x: x.decode('latin1') -+ BYTES_ORD = ord -+ from cStringIO import StringIO as BYTES_IO -+ def fprintf(f, fmt, *vargs): -+ if fmt.endswith('\n'): -+ print(fmt[:-1] % vargs, file=f) -+ else: -+ print(fmt % vargs, end=' ', file=f) -+ try: -+ EXCEL_TEXT_TYPES = basestring # xlwt: isinstance(obj, EXCEL_TEXT_TYPES) -+ except NameError: -+ EXCEL_TEXT_TYPES = (str, unicode) -+ REPR = repr -+ xrange = xrange -+ # following used only to overcome 2.x ElementTree gimmick which -+ # returns text as `str` if it's ascii, otherwise `unicode` -+ ensure_unicode = unicode # used only in xlsx.py -diff --git a/webhub/xlrd/timemachine.pyc b/webhub/xlrd/timemachine.pyc -new file mode 100644 -index 0000000..dc718e5 -Binary files /dev/null and b/webhub/xlrd/timemachine.pyc differ -diff --git a/webhub/xlrd/xldate.py b/webhub/xlrd/xldate.py -new file mode 100644 -index 0000000..dc7b9c8 ---- /dev/null -+++ b/webhub/xlrd/xldate.py -@@ -0,0 +1,213 @@ -+# -*- coding: cp1252 -*- -+ -+# No part of the content of this file was derived from the works of David Giffin. -+ -+## -+#

Copyright 2005-2008 Stephen John Machin, Lingfo Pty Ltd

-+#

This module is part of the xlrd package, which is released under a BSD-style licence.

-+# -+#

Provides function(s) for dealing with Microsoft Excel dates.

-+## -+ -+# 2008-10-18 SJM Fix bug in xldate_from_date_tuple (affected some years after 2099) -+ -+# The conversion from days to (year, month, day) starts with -+# an integral "julian day number" aka JDN. -+# FWIW, JDN 0 corresponds to noon on Monday November 24 in Gregorian year -4713. -+# More importantly: -+# Noon on Gregorian 1900-03-01 (day 61 in the 1900-based system) is JDN 2415080.0 -+# Noon on Gregorian 1904-01-02 (day 1 in the 1904-based system) is JDN 2416482.0 -+import datetime -+ -+_JDN_delta = (2415080 - 61, 2416482 - 1) -+assert _JDN_delta[1] - _JDN_delta[0] == 1462 -+ -+# Pre-calculate the datetime epochs for efficiency. -+epoch_1904 = datetime.datetime(1904, 1, 1) -+epoch_1900 = datetime.datetime(1899, 12, 31) -+epoch_1900_minus_1 = datetime.datetime(1899, 12, 30) -+ -+class XLDateError(ValueError): pass -+ -+class XLDateNegative(XLDateError): pass -+class XLDateAmbiguous(XLDateError): pass -+class XLDateTooLarge(XLDateError): pass -+class XLDateBadDatemode(XLDateError): pass -+class XLDateBadTuple(XLDateError): pass -+ -+_XLDAYS_TOO_LARGE = (2958466, 2958466 - 1462) # This is equivalent to 10000-01-01 -+ -+## -+# Convert an Excel number (presumed to represent a date, a datetime or a time) into -+# a tuple suitable for feeding to datetime or mx.DateTime constructors. -+# @param xldate The Excel number -+# @param datemode 0: 1900-based, 1: 1904-based. -+#
WARNING: when using this function to -+# interpret the contents of a workbook, you should pass in the Book.datemode -+# attribute of that workbook. Whether -+# the workbook has ever been anywhere near a Macintosh is irrelevant. -+# @return Gregorian (year, month, day, hour, minute, nearest_second). -+#
Special case: if 0.0 <= xldate < 1.0, it is assumed to represent a time; -+# (0, 0, 0, hour, minute, second) will be returned. -+#
Note: 1904-01-01 is not regarded as a valid date in the datemode 1 system; its "serial number" -+# is zero. -+# @throws XLDateNegative xldate < 0.00 -+# @throws XLDateAmbiguous The 1900 leap-year problem (datemode == 0 and 1.0 <= xldate < 61.0) -+# @throws XLDateTooLarge Gregorian year 10000 or later -+# @throws XLDateBadDatemode datemode arg is neither 0 nor 1 -+# @throws XLDateError Covers the 4 specific errors -+ -+def xldate_as_tuple(xldate, datemode): -+ if datemode not in (0, 1): -+ raise XLDateBadDatemode(datemode) -+ if xldate == 0.00: -+ return (0, 0, 0, 0, 0, 0) -+ if xldate < 0.00: -+ raise XLDateNegative(xldate) -+ xldays = int(xldate) -+ frac = xldate - xldays -+ seconds = int(round(frac * 86400.0)) -+ assert 0 <= seconds <= 86400 -+ if seconds == 86400: -+ hour = minute = second = 0 -+ xldays += 1 -+ else: -+ # second = seconds % 60; minutes = seconds // 60 -+ minutes, second = divmod(seconds, 60) -+ # minute = minutes % 60; hour = minutes // 60 -+ hour, minute = divmod(minutes, 60) -+ if xldays >= _XLDAYS_TOO_LARGE[datemode]: -+ raise XLDateTooLarge(xldate) -+ -+ if xldays == 0: -+ return (0, 0, 0, hour, minute, second) -+ -+ if xldays < 61 and datemode == 0: -+ raise XLDateAmbiguous(xldate) -+ -+ jdn = xldays + _JDN_delta[datemode] -+ yreg = ((((jdn * 4 + 274277) // 146097) * 3 // 4) + jdn + 1363) * 4 + 3 -+ mp = ((yreg % 1461) // 4) * 535 + 333 -+ d = ((mp % 16384) // 535) + 1 -+ # mp /= 16384 -+ mp >>= 14 -+ if mp >= 10: -+ return ((yreg // 1461) - 4715, mp - 9, d, hour, minute, second) -+ else: -+ return ((yreg // 1461) - 4716, mp + 3, d, hour, minute, second) -+ -+ -+## -+# Convert an Excel date/time number into a datetime.datetime object. -+# -+# @param xldate The Excel number -+# @param datemode 0: 1900-based, 1: 1904-based. -+# -+# @return a datetime.datetime() object. -+# -+def xldate_as_datetime(xldate, datemode): -+ """Convert an Excel date/time number into a datetime.datetime object.""" -+ -+ # Set the epoch based on the 1900/1904 datemode. -+ if datemode: -+ epoch = epoch_1904 -+ else: -+ if xldate < 60: -+ epoch = epoch_1900 -+ else: -+ # Workaround Excel 1900 leap year bug by adjusting the epoch. -+ epoch = epoch_1900_minus_1 -+ -+ # The integer part of the Excel date stores the number of days since -+ # the epoch and the fractional part stores the percentage of the day. -+ days = int(xldate) -+ fraction = xldate - days -+ -+ # Get the the integer and decimal seconds in Excel's millisecond resolution. -+ seconds = int(round(fraction * 86400000.0)) -+ seconds, milliseconds = divmod(seconds, 1000) -+ -+ return epoch + datetime.timedelta(days, seconds, 0, milliseconds) -+ -+ -+# === conversions from date/time to xl numbers -+ -+def _leap(y): -+ if y % 4: return 0 -+ if y % 100: return 1 -+ if y % 400: return 0 -+ return 1 -+ -+_days_in_month = (None, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) -+ -+## -+# Convert a date tuple (year, month, day) to an Excel date. -+# @param year Gregorian year. -+# @param month 1 <= month <= 12 -+# @param day 1 <= day <= last day of that (year, month) -+# @param datemode 0: 1900-based, 1: 1904-based. -+# @throws XLDateAmbiguous The 1900 leap-year problem (datemode == 0 and 1.0 <= xldate < 61.0) -+# @throws XLDateBadDatemode datemode arg is neither 0 nor 1 -+# @throws XLDateBadTuple (year, month, day) is too early/late or has invalid component(s) -+# @throws XLDateError Covers the specific errors -+ -+def xldate_from_date_tuple(date_tuple, datemode): -+ """Create an excel date from a tuple of (year, month, day)""" -+ year, month, day = date_tuple -+ -+ if datemode not in (0, 1): -+ raise XLDateBadDatemode(datemode) -+ -+ if year == 0 and month == 0 and day == 0: -+ return 0.00 -+ -+ if not (1900 <= year <= 9999): -+ raise XLDateBadTuple("Invalid year: %r" % ((year, month, day),)) -+ if not (1 <= month <= 12): -+ raise XLDateBadTuple("Invalid month: %r" % ((year, month, day),)) -+ if day < 1 \ -+ or (day > _days_in_month[month] and not(day == 29 and month == 2 and _leap(year))): -+ raise XLDateBadTuple("Invalid day: %r" % ((year, month, day),)) -+ -+ Yp = year + 4716 -+ M = month -+ if M <= 2: -+ Yp = Yp - 1 -+ Mp = M + 9 -+ else: -+ Mp = M - 3 -+ jdn = (1461 * Yp // 4) + ((979 * Mp + 16) // 32) + \ -+ day - 1364 - (((Yp + 184) // 100) * 3 // 4) -+ xldays = jdn - _JDN_delta[datemode] -+ if xldays <= 0: -+ raise XLDateBadTuple("Invalid (year, month, day): %r" % ((year, month, day),)) -+ if xldays < 61 and datemode == 0: -+ raise XLDateAmbiguous("Before 1900-03-01: %r" % ((year, month, day),)) -+ return float(xldays) -+ -+## -+# Convert a time tuple (hour, minute, second) to an Excel "date" value (fraction of a day). -+# @param hour 0 <= hour < 24 -+# @param minute 0 <= minute < 60 -+# @param second 0 <= second < 60 -+# @throws XLDateBadTuple Out-of-range hour, minute, or second -+ -+def xldate_from_time_tuple(time_tuple): -+ """Create an excel date from a tuple of (hour, minute, second)""" -+ hour, minute, second = time_tuple -+ if 0 <= hour < 24 and 0 <= minute < 60 and 0 <= second < 60: -+ return ((second / 60.0 + minute) / 60.0 + hour) / 24.0 -+ raise XLDateBadTuple("Invalid (hour, minute, second): %r" % ((hour, minute, second),)) -+ -+## -+# Convert a datetime tuple (year, month, day, hour, minute, second) to an Excel date value. -+# For more details, refer to other xldate_from_*_tuple functions. -+# @param datetime_tuple (year, month, day, hour, minute, second) -+# @param datemode 0: 1900-based, 1: 1904-based. -+ -+def xldate_from_datetime_tuple(datetime_tuple, datemode): -+ return ( -+ xldate_from_date_tuple(datetime_tuple[:3], datemode) -+ + -+ xldate_from_time_tuple(datetime_tuple[3:]) -+ ) -diff --git a/webhub/xlrd/xldate.pyc b/webhub/xlrd/xldate.pyc -new file mode 100644 -index 0000000..7b5ca3a -Binary files /dev/null and b/webhub/xlrd/xldate.pyc differ -diff --git a/webhub/xlrd/xlsx.py b/webhub/xlrd/xlsx.py -new file mode 100644 -index 0000000..53fbb89 ---- /dev/null -+++ b/webhub/xlrd/xlsx.py -@@ -0,0 +1,801 @@ -+## -+# Portions copyright (c) 2008-2012 Stephen John Machin, Lingfo Pty Ltd -+# This module is part of the xlrd package, which is released under a BSD-style licence. -+## -+ -+from __future__ import print_function, unicode_literals -+ -+DEBUG = 0 -+ -+import sys -+import re -+from .timemachine import * -+from .book import Book, Name -+from .biffh import error_text_from_code, XLRDError, XL_CELL_BLANK, XL_CELL_TEXT, XL_CELL_BOOLEAN, XL_CELL_ERROR -+from .formatting import is_date_format_string, Format, XF -+from .sheet import Sheet -+ -+DLF = sys.stdout # Default Log File -+ -+ET = None -+ET_has_iterparse = False -+ -+def ensure_elementtree_imported(verbosity, logfile): -+ global ET, ET_has_iterparse -+ if ET is not None: -+ return -+ if "IronPython" in sys.version: -+ import xml.etree.ElementTree as ET -+ #### 2.7.2.1: fails later with -+ #### NotImplementedError: iterparse is not supported on IronPython. (CP #31923) -+ else: -+ try: import xml.etree.cElementTree as ET -+ except ImportError: -+ try: import cElementTree as ET -+ except ImportError: -+ try: import lxml.etree as ET -+ except ImportError: -+ try: import xml.etree.ElementTree as ET -+ except ImportError: -+ try: import elementtree.ElementTree as ET -+ except ImportError: -+ raise Exception("Failed to import an ElementTree implementation") -+ if hasattr(ET, 'iterparse'): -+ _dummy_stream = BYTES_IO(b'') -+ try: -+ ET.iterparse(_dummy_stream) -+ ET_has_iterparse = True -+ except NotImplementedError: -+ pass -+ if verbosity: -+ etree_version = repr([ -+ (item, getattr(ET, item)) -+ for item in ET.__dict__.keys() -+ if item.lower().replace('_', '') == 'version' -+ ]) -+ print(ET.__file__, ET.__name__, etree_version, ET_has_iterparse, file=logfile) -+ -+def split_tag(tag): -+ pos = tag.rfind('}') + 1 -+ if pos >= 2: -+ return tag[:pos], tag[pos:] -+ return '', tag -+ -+def augment_keys(adict, uri): -+ # uri must already be enclosed in {} -+ for x in list(adict.keys()): -+ adict[uri + x] = adict[x] -+ -+_UPPERCASE_1_REL_INDEX = {} # Used in fast conversion of column names (e.g. "XFD") to indices (16383) -+for _x in xrange(26): -+ _UPPERCASE_1_REL_INDEX["ABCDEFGHIJKLMNOPQRSTUVWXYZ"[_x]] = _x + 1 -+for _x in "123456789": -+ _UPPERCASE_1_REL_INDEX[_x] = 0 -+del _x -+ -+def cell_name_to_rowx_colx(cell_name, letter_value=_UPPERCASE_1_REL_INDEX): -+ # Extract column index from cell name -+ # A => 0, Z =>25, AA => 26, XFD => 16383 -+ colx = 0 -+ charx = -1 -+ try: -+ for c in cell_name: -+ charx += 1 -+ lv = letter_value[c] -+ if lv: -+ colx = colx * 26 + lv -+ else: # start of row number; can't be '0' -+ colx = colx - 1 -+ assert 0 <= colx < X12_MAX_COLS -+ break -+ except KeyError: -+ raise Exception('Unexpected character %r in cell name %r' % (c, cell_name)) -+ rowx = int(cell_name[charx:]) - 1 -+ return rowx, colx -+ -+error_code_from_text = {} -+for _code, _text in error_text_from_code.items(): -+ error_code_from_text[_text] = _code -+ -+# === X12 === Excel 2007 .xlsx =============================================== -+ -+U_SSML12 = "{http://schemas.openxmlformats.org/spreadsheetml/2006/main}" -+U_ODREL = "{http://schemas.openxmlformats.org/officeDocument/2006/relationships}" -+U_PKGREL = "{http://schemas.openxmlformats.org/package/2006/relationships}" -+U_CP = "{http://schemas.openxmlformats.org/package/2006/metadata/core-properties}" -+U_DC = "{http://purl.org/dc/elements/1.1/}" -+U_DCTERMS = "{http://purl.org/dc/terms/}" -+XML_SPACE_ATTR = "{http://www.w3.org/XML/1998/namespace}space" -+XML_WHITESPACE = "\t\n \r" -+X12_MAX_ROWS = 2 ** 20 -+X12_MAX_COLS = 2 ** 14 -+V_TAG = U_SSML12 + 'v' # cell child: value -+F_TAG = U_SSML12 + 'f' # cell child: formula -+IS_TAG = U_SSML12 + 'is' # cell child: inline string -+ -+def unescape(s, -+ subber=re.compile(r'_x[0-9A-Fa-f]{4,4}_', re.UNICODE).sub, -+ repl=lambda mobj: unichr(int(mobj.group(0)[2:6], 16)), -+ ): -+ if "_" in s: -+ return subber(repl, s) -+ return s -+ -+def cooked_text(self, elem): -+ t = elem.text -+ if t is None: -+ return '' -+ if elem.get(XML_SPACE_ATTR) != 'preserve': -+ t = t.strip(XML_WHITESPACE) -+ return ensure_unicode(unescape(t)) -+ -+def get_text_from_si_or_is(self, elem, r_tag=U_SSML12+'r', t_tag=U_SSML12 +'t'): -+ "Returns unescaped unicode" -+ accum = [] -+ for child in elem: -+ # self.dump_elem(child) -+ tag = child.tag -+ if tag == t_tag: -+ t = cooked_text(self, child) -+ if t: # note: .text attribute can be None -+ accum.append(t) -+ elif tag == r_tag: -+ for tnode in child: -+ if tnode.tag == t_tag: -+ t = cooked_text(self, tnode) -+ if t: -+ accum.append(t) -+ return ''.join(accum) -+ -+def map_attributes(amap, elem, obj): -+ for xml_attr, obj_attr, cnv_func_or_const in amap: -+ if not xml_attr: -+ setattr(obj, obj_attr, cnv_func_or_const) -+ continue -+ if not obj_attr: continue #### FIX ME #### -+ raw_value = elem.get(xml_attr) -+ cooked_value = cnv_func_or_const(raw_value) -+ setattr(obj, obj_attr, cooked_value) -+ -+def cnv_ST_Xstring(s): -+ if s is None: return "" -+ return ensure_unicode(s) -+ -+def cnv_xsd_unsignedInt(s): -+ if not s: -+ return None -+ value = int(s) -+ assert value >= 0 -+ return value -+ -+def cnv_xsd_boolean(s): -+ if not s: -+ return 0 -+ if s in ("1", "true", "on"): -+ return 1 -+ if s in ("0", "false", "off"): -+ return 0 -+ raise ValueError("unexpected xsd:boolean value: %r" % s) -+ -+ -+_defined_name_attribute_map = ( -+ ("name", "name", cnv_ST_Xstring, ), -+ ("comment", "", cnv_ST_Xstring, ), -+ ("customMenu", "", cnv_ST_Xstring, ), -+ ("description", "", cnv_ST_Xstring, ), -+ ("help", "", cnv_ST_Xstring, ), -+ ("statusBar", "", cnv_ST_Xstring, ), -+ ("localSheetId", "scope", cnv_xsd_unsignedInt, ), -+ ("hidden", "hidden", cnv_xsd_boolean, ), -+ ("function", "func", cnv_xsd_boolean, ), -+ ("vbProcedure", "vbasic", cnv_xsd_boolean, ), -+ ("xlm", "macro", cnv_xsd_boolean, ), -+ ("functionGroupId", "funcgroup", cnv_xsd_unsignedInt, ), -+ ("shortcutKey", "", cnv_ST_Xstring, ), -+ ("publishToServer", "", cnv_xsd_boolean, ), -+ ("workbookParameter", "", cnv_xsd_boolean, ), -+ ("", "any_err", 0, ), -+ ("", "any_external", 0, ), -+ ("", "any_rel", 0, ), -+ ("", "basic_formula_len", 0, ), -+ ("", "binary", 0, ), -+ ("", "builtin", 0, ), -+ ("", "complex", 0, ), -+ ("", "evaluated", 0, ), -+ ("", "excel_sheet_index", 0, ), -+ ("", "excel_sheet_num", 0, ), -+ ("", "option_flags", 0, ), -+ ("", "result", None, ), -+ ("", "stack", None, ), -+ ) -+ -+def make_name_access_maps(bk): -+ name_and_scope_map = {} # (name.lower(), scope): Name_object -+ name_map = {} # name.lower() : list of Name_objects (sorted in scope order) -+ num_names = len(bk.name_obj_list) -+ for namex in xrange(num_names): -+ nobj = bk.name_obj_list[namex] -+ name_lcase = nobj.name.lower() -+ key = (name_lcase, nobj.scope) -+ if key in name_and_scope_map: -+ msg = 'Duplicate entry %r in name_and_scope_map' % (key, ) -+ if 0: -+ raise XLRDError(msg) -+ else: -+ if bk.verbosity: -+ print(msg, file=bk.logfile) -+ name_and_scope_map[key] = nobj -+ if name_lcase in name_map: -+ name_map[name_lcase].append((nobj.scope, nobj)) -+ else: -+ name_map[name_lcase] = [(nobj.scope, nobj)] -+ for key in name_map.keys(): -+ alist = name_map[key] -+ alist.sort() -+ name_map[key] = [x[1] for x in alist] -+ bk.name_and_scope_map = name_and_scope_map -+ bk.name_map = name_map -+ -+class X12General(object): -+ -+ def process_stream(self, stream, heading=None): -+ if self.verbosity >= 2 and heading is not None: -+ fprintf(self.logfile, "\n=== %s ===\n", heading) -+ self.tree = ET.parse(stream) -+ getmethod = self.tag2meth.get -+ for elem in self.tree.getiterator(): -+ if self.verbosity >= 3: -+ self.dump_elem(elem) -+ meth = getmethod(elem.tag) -+ if meth: -+ meth(self, elem) -+ self.finish_off() -+ -+ def finish_off(self): -+ pass -+ -+ def dump_elem(self, elem): -+ fprintf(self.logfile, -+ "===\ntag=%r len=%d attrib=%r text=%r tail=%r\n", -+ split_tag(elem.tag)[1], len(elem), elem.attrib, elem.text, elem.tail) -+ -+ def dumpout(self, fmt, *vargs): -+ text = (12 * ' ' + fmt + '\n') % vargs -+ self.logfile.write(text) -+ -+class X12Book(X12General): -+ -+ def __init__(self, bk, logfile=DLF, verbosity=False): -+ self.bk = bk -+ self.logfile = logfile -+ self.verbosity = verbosity -+ self.bk.nsheets = 0 -+ self.bk.props = {} -+ self.relid2path = {} -+ self.relid2reltype = {} -+ self.sheet_targets = [] # indexed by sheetx -+ self.sheetIds = [] # indexed by sheetx -+ -+ core_props_menu = { -+ U_CP+"lastModifiedBy": ("last_modified_by", cnv_ST_Xstring), -+ U_DC+"creator": ("creator", cnv_ST_Xstring), -+ U_DCTERMS+"modified": ("modified", cnv_ST_Xstring), -+ U_DCTERMS+"created": ("created", cnv_ST_Xstring), -+ } -+ -+ def process_coreprops(self, stream): -+ if self.verbosity >= 2: -+ fprintf(self.logfile, "\n=== coreProps ===\n") -+ self.tree = ET.parse(stream) -+ getmenu = self.core_props_menu.get -+ props = {} -+ for elem in self.tree.getiterator(): -+ if self.verbosity >= 3: -+ self.dump_elem(elem) -+ menu = getmenu(elem.tag) -+ if menu: -+ attr, func = menu -+ value = func(elem.text) -+ props[attr] = value -+ self.bk.user_name = props.get('last_modified_by') or props.get('creator') -+ self.bk.props = props -+ if self.verbosity >= 2: -+ fprintf(self.logfile, "props: %r\n", props) -+ self.finish_off() -+ -+ def process_rels(self, stream): -+ if self.verbosity >= 2: -+ fprintf(self.logfile, "\n=== Relationships ===\n") -+ tree = ET.parse(stream) -+ r_tag = U_PKGREL + 'Relationship' -+ for elem in tree.findall(r_tag): -+ rid = elem.get('Id') -+ target = elem.get('Target') -+ reltype = elem.get('Type').split('/')[-1] -+ if self.verbosity >= 2: -+ self.dumpout('Id=%r Type=%r Target=%r', rid, reltype, target) -+ self.relid2reltype[rid] = reltype -+ # self.relid2path[rid] = 'xl/' + target -+ if target.startswith('/'): -+ self.relid2path[rid] = target[1:] # drop the / -+ else: -+ self.relid2path[rid] = 'xl/' + target -+ -+ def do_defined_name(self, elem): -+ #### UNDER CONSTRUCTION #### -+ if 0 and self.verbosity >= 3: -+ self.dump_elem(elem) -+ nobj = Name() -+ bk = self.bk -+ nobj.bk = bk -+ nobj.name_index = len(bk.name_obj_list) -+ bk.name_obj_list.append(nobj) -+ nobj.name = elem.get('name') -+ nobj.raw_formula = None # compiled bytecode formula -- not in XLSX -+ nobj.formula_text = cooked_text(self, elem) -+ map_attributes(_defined_name_attribute_map, elem, nobj) -+ if nobj.scope is None: -+ nobj.scope = -1 # global -+ if nobj.name.startswith("_xlnm."): -+ nobj.builtin = 1 -+ if self.verbosity >= 2: -+ nobj.dump(header='=== Name object ===') -+ -+ def do_defined_names(self, elem): -+ for child in elem: -+ self.do_defined_name(child) -+ make_name_access_maps(self.bk) -+ -+ def do_sheet(self, elem): -+ bk = self.bk -+ sheetx = bk.nsheets -+ # print elem.attrib -+ rid = elem.get(U_ODREL + 'id') -+ sheetId = int(elem.get('sheetId')) -+ name = unescape(ensure_unicode(elem.get('name'))) -+ reltype = self.relid2reltype[rid] -+ target = self.relid2path[rid] -+ if self.verbosity >= 2: -+ self.dumpout( -+ 'sheetx=%d sheetId=%r rid=%r type=%r name=%r', -+ sheetx, sheetId, rid, reltype, name) -+ if reltype != 'worksheet': -+ if self.verbosity >= 2: -+ self.dumpout('Ignoring sheet of type %r (name=%r)', reltype, name) -+ return -+ state = elem.get('state') -+ visibility_map = { -+ None: 0, -+ 'visible': 0, -+ 'hidden': 1, -+ 'veryHidden': 2 -+ } -+ bk._sheet_visibility.append(visibility_map[state]) -+ sheet = Sheet(bk, position=None, name=name, number=sheetx) -+ sheet.utter_max_rows = X12_MAX_ROWS -+ sheet.utter_max_cols = X12_MAX_COLS -+ bk._sheet_list.append(sheet) -+ bk._sheet_names.append(name) -+ bk.nsheets += 1 -+ self.sheet_targets.append(target) -+ self.sheetIds.append(sheetId) -+ -+ -+ def do_workbookpr(self, elem): -+ datemode = cnv_xsd_boolean(elem.get('date1904')) -+ if self.verbosity >= 2: -+ self.dumpout('datemode=%r', datemode) -+ self.bk.datemode = datemode -+ -+ tag2meth = { -+ 'definedNames': do_defined_names, -+ 'workbookPr': do_workbookpr, -+ 'sheet': do_sheet, -+ } -+ augment_keys(tag2meth, U_SSML12) -+ -+class X12SST(X12General): -+ -+ def __init__(self, bk, logfile=DLF, verbosity=0): -+ self.bk = bk -+ self.logfile = logfile -+ self.verbosity = verbosity -+ if ET_has_iterparse: -+ self.process_stream = self.process_stream_iterparse -+ else: -+ self.process_stream = self.process_stream_findall -+ -+ def process_stream_iterparse(self, stream, heading=None): -+ if self.verbosity >= 2 and heading is not None: -+ fprintf(self.logfile, "\n=== %s ===\n", heading) -+ si_tag = U_SSML12 + 'si' -+ elemno = -1 -+ sst = self.bk._sharedstrings -+ for event, elem in ET.iterparse(stream): -+ if elem.tag != si_tag: continue -+ elemno = elemno + 1 -+ if self.verbosity >= 3: -+ fprintf(self.logfile, "element #%d\n", elemno) -+ self.dump_elem(elem) -+ result = get_text_from_si_or_is(self, elem) -+ sst.append(result) -+ elem.clear() # destroy all child elements -+ if self.verbosity >= 2: -+ self.dumpout('Entries in SST: %d', len(sst)) -+ if self.verbosity >= 3: -+ for x, s in enumerate(sst): -+ fprintf(self.logfile, "SST x=%d s=%r\n", x, s) -+ -+ def process_stream_findall(self, stream, heading=None): -+ if self.verbosity >= 2 and heading is not None: -+ fprintf(self.logfile, "\n=== %s ===\n", heading) -+ self.tree = ET.parse(stream) -+ si_tag = U_SSML12 + 'si' -+ elemno = -1 -+ sst = self.bk._sharedstrings -+ for elem in self.tree.findall(si_tag): -+ elemno = elemno + 1 -+ if self.verbosity >= 3: -+ fprintf(self.logfile, "element #%d\n", elemno) -+ self.dump_elem(elem) -+ result = get_text_from_si_or_is(self, elem) -+ sst.append(result) -+ if self.verbosity >= 2: -+ self.dumpout('Entries in SST: %d', len(sst)) -+ -+class X12Styles(X12General): -+ -+ def __init__(self, bk, logfile=DLF, verbosity=0): -+ self.bk = bk -+ self.logfile = logfile -+ self.verbosity = verbosity -+ self.xf_counts = [0, 0] -+ self.xf_type = None -+ self.fmt_is_date = {} -+ for x in list(range(14, 23)) + list(range(45, 48)): #### hard-coding FIX ME #### -+ self.fmt_is_date[x] = 1 -+ # dummy entry for XF 0 in case no Styles section -+ self.bk._xf_index_to_xl_type_map[0] = 2 -+ # fill_in_standard_formats(bk) #### pre-integration kludge -+ -+ def do_cellstylexfs(self, elem): -+ self.xf_type = 0 -+ -+ def do_cellxfs(self, elem): -+ self.xf_type = 1 -+ -+ def do_numfmt(self, elem): -+ formatCode = ensure_unicode(elem.get('formatCode')) -+ numFmtId = int(elem.get('numFmtId')) -+ is_date = is_date_format_string(self.bk, formatCode) -+ self.fmt_is_date[numFmtId] = is_date -+ fmt_obj = Format(numFmtId, is_date + 2, formatCode) -+ self.bk.format_map[numFmtId] = fmt_obj -+ if self.verbosity >= 3: -+ self.dumpout('numFmtId=%d formatCode=%r is_date=%d', numFmtId, formatCode, is_date) -+ -+ def do_xf(self, elem): -+ if self.xf_type != 1: -+ #### ignoring style XFs for the moment -+ return -+ xfx = self.xf_counts[self.xf_type] -+ self.xf_counts[self.xf_type] = xfx + 1 -+ xf = XF() -+ self.bk.xf_list.append(xf) -+ self.bk.xfcount += 1 -+ numFmtId = int(elem.get('numFmtId', '0')) -+ xf.format_key = numFmtId -+ is_date = self.fmt_is_date.get(numFmtId, 0) -+ self.bk._xf_index_to_xl_type_map[xfx] = is_date + 2 -+ if self.verbosity >= 3: -+ self.dumpout( -+ 'xfx=%d numFmtId=%d', -+ xfx, numFmtId, -+ ) -+ self.dumpout(repr(self.bk._xf_index_to_xl_type_map)) -+ -+ tag2meth = { -+ 'cellStyleXfs': do_cellstylexfs, -+ 'cellXfs': do_cellxfs, -+ 'numFmt': do_numfmt, -+ 'xf': do_xf, -+ } -+ augment_keys(tag2meth, U_SSML12) -+ -+class X12Sheet(X12General): -+ -+ def __init__(self, sheet, logfile=DLF, verbosity=0): -+ self.sheet = sheet -+ self.logfile = logfile -+ self.verbosity = verbosity -+ self.rowx = -1 # We may need to count them. -+ self.bk = sheet.book -+ self.sst = self.bk._sharedstrings -+ self.merged_cells = sheet.merged_cells -+ self.warned_no_cell_name = 0 -+ self.warned_no_row_num = 0 -+ if ET_has_iterparse: -+ self.process_stream = self.own_process_stream -+ -+ def own_process_stream(self, stream, heading=None): -+ if self.verbosity >= 2 and heading is not None: -+ fprintf(self.logfile, "\n=== %s ===\n", heading) -+ getmethod = self.tag2meth.get -+ row_tag = U_SSML12 + "row" -+ self_do_row = self.do_row -+ for event, elem in ET.iterparse(stream): -+ if elem.tag == row_tag: -+ self_do_row(elem) -+ elem.clear() # destroy all child elements (cells) -+ elif elem.tag == U_SSML12 + "dimension": -+ self.do_dimension(elem) -+ elif elem.tag == U_SSML12 + "mergeCell": -+ self.do_merge_cell(elem) -+ self.finish_off() -+ -+ def process_comments_stream(self, stream): -+ root = ET.parse(stream).getroot() -+ author_list = root[0] -+ assert author_list.tag == U_SSML12 + 'authors' -+ authors = [elem.text for elem in author_list] -+ comment_list = root[1] -+ assert comment_list.tag == U_SSML12 + 'commentList' -+ cell_note_map = self.sheet.cell_note_map -+ from .sheet import Note -+ text_tag = U_SSML12 + 'text' -+ r_tag = U_SSML12 + 'r' -+ t_tag = U_SSML12 + 't' -+ for elem in comment_list.findall(U_SSML12 + 'comment'): -+ ts = elem.findall('./' + text_tag + '/' + t_tag) -+ ts += elem.findall('./' + text_tag + '/' + r_tag + '/' + t_tag) -+ ref = elem.get('ref') -+ note = Note() -+ note.author = authors[int(elem.get('authorId'))] -+ note.rowx, note.colx = coords = cell_name_to_rowx_colx(ref) -+ note.text = '' -+ for t in ts: -+ note.text += cooked_text(self, t) -+ cell_note_map[coords] = note -+ -+ def do_dimension(self, elem): -+ ref = elem.get('ref') # example: "A1:Z99" or just "A1" -+ if ref: -+ # print >> self.logfile, "dimension: ref=%r" % ref -+ last_cell_ref = ref.split(':')[-1] # example: "Z99" -+ rowx, colx = cell_name_to_rowx_colx(last_cell_ref) -+ self.sheet._dimnrows = rowx + 1 -+ self.sheet._dimncols = colx + 1 -+ -+ def do_merge_cell(self, elem): -+ # The ref attribute should be a cell range like "B1:D5". -+ ref = elem.get('ref') -+ if ref: -+ first_cell_ref, last_cell_ref = ref.split(':') -+ first_rowx, first_colx = cell_name_to_rowx_colx(first_cell_ref) -+ last_rowx, last_colx = cell_name_to_rowx_colx(last_cell_ref) -+ self.merged_cells.append((first_rowx, last_rowx + 1, -+ first_colx, last_colx + 1)) -+ -+ def do_row(self, row_elem): -+ -+ def bad_child_tag(child_tag): -+ raise Exception('cell type %s has unexpected child <%s> at rowx=%r colx=%r' % (cell_type, child_tag, rowx, colx)) -+ -+ row_number = row_elem.get('r') -+ if row_number is None: # Yes, it's optional. -+ self.rowx += 1 -+ explicit_row_number = 0 -+ if self.verbosity and not self.warned_no_row_num: -+ self.dumpout("no row number; assuming rowx=%d", self.rowx) -+ self.warned_no_row_num = 1 -+ else: -+ self.rowx = int(row_number) - 1 -+ explicit_row_number = 1 -+ assert 0 <= self.rowx < X12_MAX_ROWS -+ rowx = self.rowx -+ colx = -1 -+ if self.verbosity >= 3: -+ self.dumpout(" row_number=%r rowx=%d explicit=%d", -+ row_number, self.rowx, explicit_row_number) -+ letter_value = _UPPERCASE_1_REL_INDEX -+ for cell_elem in row_elem: -+ cell_name = cell_elem.get('r') -+ if cell_name is None: # Yes, it's optional. -+ colx += 1 -+ if self.verbosity and not self.warned_no_cell_name: -+ self.dumpout("no cellname; assuming rowx=%d colx=%d", rowx, colx) -+ self.warned_no_cell_name = 1 -+ else: -+ # Extract column index from cell name -+ # A => 0, Z =>25, AA => 26, XFD => 16383 -+ colx = 0 -+ charx = -1 -+ try: -+ for c in cell_name: -+ charx += 1 -+ if c == '$': -+ continue -+ lv = letter_value[c] -+ if lv: -+ colx = colx * 26 + lv -+ else: # start of row number; can't be '0' -+ colx = colx - 1 -+ assert 0 <= colx < X12_MAX_COLS -+ break -+ except KeyError: -+ raise Exception('Unexpected character %r in cell name %r' % (c, cell_name)) -+ if explicit_row_number and cell_name[charx:] != row_number: -+ raise Exception('cell name %r but row number is %r' % (cell_name, row_number)) -+ xf_index = int(cell_elem.get('s', '0')) -+ cell_type = cell_elem.get('t', 'n') -+ tvalue = None -+ formula = None -+ if cell_type == 'n': -+ # n = number. Most frequent type. -+ # child contains plain text which can go straight into float() -+ # OR there's no text in which case it's a BLANK cell -+ for child in cell_elem: -+ child_tag = child.tag -+ if child_tag == V_TAG: -+ tvalue = child.text -+ elif child_tag == F_TAG: -+ formula = cooked_text(self, child) -+ else: -+ raise Exception('unexpected tag %r' % child_tag) -+ if not tvalue: -+ if self.bk.formatting_info: -+ self.sheet.put_cell(rowx, colx, XL_CELL_BLANK, '', xf_index) -+ else: -+ self.sheet.put_cell(rowx, colx, None, float(tvalue), xf_index) -+ elif cell_type == "s": -+ # s = index into shared string table. 2nd most frequent type -+ # child contains plain text which can go straight into int() -+ for child in cell_elem: -+ child_tag = child.tag -+ if child_tag == V_TAG: -+ tvalue = child.text -+ elif child_tag == F_TAG: -+ # formula not expected here, but gnumeric does it. -+ formula = child.text -+ else: -+ bad_child_tag(child_tag) -+ if not tvalue: -+ # -+ if self.bk.formatting_info: -+ self.sheet.put_cell(rowx, colx, XL_CELL_BLANK, '', xf_index) -+ else: -+ value = self.sst[int(tvalue)] -+ self.sheet.put_cell(rowx, colx, XL_CELL_TEXT, value, xf_index) -+ elif cell_type == "str": -+ # str = string result from formula. -+ # Should have (formula) child; however in one file, all text cells are str with no formula. -+ # child can contain escapes -+ for child in cell_elem: -+ child_tag = child.tag -+ if child_tag == V_TAG: -+ tvalue = cooked_text(self, child) -+ elif child_tag == F_TAG: -+ formula = cooked_text(self, child) -+ else: -+ bad_child_tag(child_tag) -+ # assert tvalue is not None and formula is not None -+ # Yuk. Fails with file created by gnumeric -- no tvalue! -+ self.sheet.put_cell(rowx, colx, XL_CELL_TEXT, tvalue, xf_index) -+ elif cell_type == "b": -+ # b = boolean -+ # child contains "0" or "1" -+ # Maybe the data should be converted with cnv_xsd_boolean; -+ # ECMA standard is silent; Excel 2007 writes 0 or 1 -+ for child in cell_elem: -+ child_tag = child.tag -+ if child_tag == V_TAG: -+ tvalue = child.text -+ elif child_tag == F_TAG: -+ formula = cooked_text(self, child) -+ else: -+ bad_child_tag(child_tag) -+ self.sheet.put_cell(rowx, colx, XL_CELL_BOOLEAN, int(tvalue), xf_index) -+ elif cell_type == "e": -+ # e = error -+ # child contains e.g. "#REF!" -+ for child in cell_elem: -+ child_tag = child.tag -+ if child_tag == V_TAG: -+ tvalue = child.text -+ elif child_tag == F_TAG: -+ formula = cooked_text(self, child) -+ else: -+ bad_child_tag(child_tag) -+ value = error_code_from_text[tvalue] -+ self.sheet.put_cell(rowx, colx, XL_CELL_ERROR, value, xf_index) -+ elif cell_type == "inlineStr": -+ # Not expected in files produced by Excel. -+ # Only possible child is . -+ # It's a way of allowing 3rd party s/w to write text (including rich text) cells -+ # without having to build a shared string table -+ for child in cell_elem: -+ child_tag = child.tag -+ if child_tag == IS_TAG: -+ tvalue = get_text_from_si_or_is(self, child) -+ else: -+ bad_child_tag(child_tag) -+ assert tvalue is not None -+ self.sheet.put_cell(rowx, colx, XL_CELL_TEXT, tvalue, xf_index) -+ else: -+ raise Exception("Unknown cell type %r in rowx=%d colx=%d" % (cell_type, rowx, colx)) -+ -+ tag2meth = { -+ 'row': do_row, -+ } -+ augment_keys(tag2meth, U_SSML12) -+ -+def open_workbook_2007_xml( -+ zf, -+ component_names, -+ logfile=sys.stdout, -+ verbosity=0, -+ use_mmap=0, -+ formatting_info=0, -+ on_demand=0, -+ ragged_rows=0, -+ ): -+ ensure_elementtree_imported(verbosity, logfile) -+ bk = Book() -+ bk.logfile = logfile -+ bk.verbosity = verbosity -+ bk.formatting_info = formatting_info -+ if formatting_info: -+ raise NotImplementedError("formatting_info=True not yet implemented") -+ bk.use_mmap = False #### Not supported initially -+ bk.on_demand = on_demand -+ if on_demand: -+ if verbosity: -+ print("WARNING *** on_demand=True not yet implemented; falling back to False", file=bk.logfile) -+ bk.on_demand = False -+ bk.ragged_rows = ragged_rows -+ -+ x12book = X12Book(bk, logfile, verbosity) -+ zflo = zf.open('xl/_rels/workbook.xml.rels') -+ x12book.process_rels(zflo) -+ del zflo -+ zflo = zf.open('xl/workbook.xml') -+ x12book.process_stream(zflo, 'Workbook') -+ del zflo -+ props_name = 'docProps/core.xml' -+ if props_name in component_names: -+ zflo = zf.open(props_name) -+ x12book.process_coreprops(zflo) -+ -+ x12sty = X12Styles(bk, logfile, verbosity) -+ if 'xl/styles.xml' in component_names: -+ zflo = zf.open('xl/styles.xml') -+ x12sty.process_stream(zflo, 'styles') -+ del zflo -+ else: -+ # seen in MS sample file MergedCells.xlsx -+ pass -+ -+ sst_fname = 'xl/sharedStrings.xml' -+ x12sst = X12SST(bk, logfile, verbosity) -+ if sst_fname in component_names: -+ zflo = zf.open(sst_fname) -+ x12sst.process_stream(zflo, 'SST') -+ del zflo -+ -+ for sheetx in range(bk.nsheets): -+ fname = x12book.sheet_targets[sheetx] -+ zflo = zf.open(fname) -+ sheet = bk._sheet_list[sheetx] -+ x12sheet = X12Sheet(sheet, logfile, verbosity) -+ heading = "Sheet %r (sheetx=%d) from %r" % (sheet.name, sheetx, fname) -+ x12sheet.process_stream(zflo, heading) -+ del zflo -+ comments_fname = 'xl/comments%d.xml' % (sheetx + 1) -+ if comments_fname in component_names: -+ comments_stream = zf.open(comments_fname) -+ x12sheet.process_comments_stream(comments_stream) -+ del comments_stream -+ -+ sheet.tidy_dimensions() -+ -+ return bk - -commit b3faea419eac046f6c7365d35ac0de6c2a73e9b0 -Author: desaivaibhavi -Date: Sun Jul 20 10:38:05 2014 +0000 - - api complete, small bugs solved - -diff --git a/ui/peacetrack.html b/ui/peacetrack.html -index 38733d8..4f24747 100644 ---- a/ui/peacetrack.html -+++ b/ui/peacetrack.html -@@ -14,8 +14,8 @@ email : ranihaileydesai@gmail.com - {% include "header.html" %} -





-
--

Summary

--

Volunteer

-+

Summary

-+

Volunteer

-

Graph

-
- -diff --git a/ui/summary.html b/ui/summary.html -index 793065e..605c41b 100644 ---- a/ui/summary.html -+++ b/ui/summary.html -@@ -5,4 +5,98 @@ Github username : desaivaibhavi - email : ranihaileydesai@gmail.com - --> - -- -\ No newline at end of file -+ -+ -+ -+ -+ -+ PeaceTrack | Summary -+ -+ -+ {% include "header.html" %} -+





-+

PeaceTrack : Summary

-+
-+

-+ -+ -+ Details by Post

-+ -+ {%if all_post|length ==0 %} -+

There are No Posts right now.











-+ {% else %} -+ -+ {% for post in all_post %} -+ -+ Name of the post : {{post.post_name}}
-+ Region : {{post.post_region}}
-+ Sector : {{post.sector}}
-+ {% endfor %} -+ -+ {% endif %} -+
-+ Details by Sector

-+ -+ {%if all_sector|length ==0 %} -+

There are No Sectors right now.











-+ {% else %} -+ -+ {% for sect in all_sector %} -+ -+ -+ Name of the sector : {{sect.sector_name}}
-+ Description of the sector : {{sect.sector_desc}}
-+ Code : {{sect.sector_code}}
-+ -+ -+ {% endfor %} -+ -+ {% endif %} -+ -+
-+ Details by Project

-+ -+ {%if all_project|length ==0 %} -+

There are No Projects right now.











-+ {% else %} -+ -+ {% for proj in all_project %} -+ -+ Name of the project : {{proj.project_name}}
-+ Purpose : {{proj.project_purpose}}
-+ Sector : {{proj.project_sector}}
-+ -+ -+ -+ {% endfor %} -+ -+ {% endif %} -+ -+
-+ Details by Volunteer

-+ {%if all_vol|length ==0 %} -+

There are No Volunteers right now.











-+ {% else %} -+ -+ {% for vol in all_vol %} -+ -+ Name of volunteer : {{vol.vol_name}}
-+ Sector : {{vol.vol_sector}}
-+ Post : {{vol.vol_ptpost}}
-+ Activity : {{vol.vol_activity}}
-+ Measurement : {{vol.vol_meas}}
-+ Cohurt : {{vol.vol_cohurt}}
-+
-+ {% endfor %} -+ -+ {% endif %} -+
-+ -+
-+
-+

-+ {% include "footer.html" %} -+ -+ -+ -+ -diff --git a/ui/volunteer.html b/ui/volunteer.html -index 5e1db63..bae233b 100644 ---- a/ui/volunteer.html -+++ b/ui/volunteer.html -@@ -25,27 +25,17 @@ email : ranihaileydesai@gmail.com -

There are No Volunteers right now.











- {% else %} - -- -- -- -- -- -- -- -- -- -- -- {% for vol in all_vol %} -- -- -- -- {% endfor %} -- -- -- -- --

Post

Action

{{vol.}}     --
-+ {% for vol in all_vol %} -+ -+ Name of volunteer : {{vol.vol_name}}
-+ Sector : {{vol.vol_sector}}
-+ Post : {{vol.vol_ptpost}}
-+ Activity : {{vol.vol_activity}}
-+ Measurement : {{vol.vol_meas}}
-+ Cohurt : {{vol.vol_cohurt}}
-+
-+ {% endfor %} -+ - {% endif %} - - -diff --git a/webhub/models.pyc b/webhub/models.pyc -index 58d2434..dddb1e7 100644 -Binary files a/webhub/models.pyc and b/webhub/models.pyc differ -diff --git a/webhub/urls.py b/webhub/urls.py -index 5f25357..7a47f57 100644 ---- a/webhub/urls.py -+++ b/webhub/urls.py -@@ -69,7 +69,7 @@ urlpatterns = patterns('', - url(r'^details/$', views.details, name='details'), - url(r'^helpPC/$', views.helpPC, name='helpPC'), - url(r'^volunteer/$', views.volunteer, name='volunteer'), -- -+ url(r'^summary/$', views.summary, name='summary'), - ) - - -diff --git a/webhub/urls.pyc b/webhub/urls.pyc -index d8e1bc3..dab8981 100644 -Binary files a/webhub/urls.pyc and b/webhub/urls.pyc differ -diff --git a/webhub/views.py b/webhub/views.py -index b77b9ad..776e4d9 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -1441,7 +1441,15 @@ def peacetrack(request): - #Called when a user wants to see the details of a volunteer. - def volunteer(request): - all_vol = Volunteer.objects.all() -- return HttpResponse(jinja_environ.get_template('volunteer.html').render({"all_vol":all_posts, "pcuser":request.user.pcuser})) -+ return HttpResponse(jinja_environ.get_template('volunteer.html').render({"all_vol":all_vol, "pcuser":request.user.pcuser})) -+ -+#Called when a user wants to see the summary of peacetrack volunteer db -+def summary(request): -+ all_post = PTPost.objects.all() -+ all_sector = Sector.objects.all() -+ all_project = Project.objects.all() -+ all_vol = Volunteer.objects.all() -+ return HttpResponse(jinja_environ.get_template('summary.html').render({"all_vol":all_vol,"all_post":all_post,"all_sector":all_sector, "all_project":all_project,"pcuser":request.user.pcuser})) - - - #called when user wishes to go to the Peacetrack from dashboard -diff --git a/webhub/views.pyc b/webhub/views.pyc -index ee2eefc..af5b4e2 100644 -Binary files a/webhub/views.pyc and b/webhub/views.pyc differ - -commit 6cc4e855cf91737d549eef3f059e049c410b13bb -Author: desaivaibhavi -Date: Mon Jul 14 13:24:14 2014 +0000 - - email field added - -diff --git a/ui/volunteer.html b/ui/volunteer.html -index 5a8361e..5e1db63 100644 ---- a/ui/volunteer.html -+++ b/ui/volunteer.html -@@ -5,4 +5,55 @@ Github username : desaivaibhavi - email : ranihaileydesai@gmail.com - --> - -- -\ No newline at end of file -+ -+ -+ -+ -+ -+ PeaceTrack | volunteer -+ -+ -+ {% include "header.html" %} -+





-+

PeaceTrack : Volunteer details

-+
-+

-+ -+ -+ -+ {%if all_vol|length ==0 %} -+

There are No Volunteers right now.











-+ {% else %} -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ {% for vol in all_vol %} -+ -+ -+ -+ {% endfor %} -+ -+ -+ -+ -+

Post

Action

{{vol.}}     -+
-+ {% endif %} -+ -+ -+
-+
-+

-+ {% include "footer.html" %} -+ -+ -+ -+ -diff --git a/webhub/models.py b/webhub/models.py -index 7192e77..bd1a959 100644 ---- a/webhub/models.py -+++ b/webhub/models.py -@@ -282,8 +282,8 @@ class Measurement(models.Model): - class Volunteer(models.Model): - #username - vol_name = models.CharField(max_length=300) -- #password -- -+ #email -+ vol_email = models.CharField(max_length=300) - #sector - vol_sector = models.ForeignKey(Sector, null=False, related_name='vol_sector') - #country -diff --git a/webhub/urls.py b/webhub/urls.py -index ace3d40..5f25357 100644 ---- a/webhub/urls.py -+++ b/webhub/urls.py -@@ -68,6 +68,8 @@ urlpatterns = patterns('', - url(r'^policies/$', views.policies, name='policies'), - url(r'^details/$', views.details, name='details'), - url(r'^helpPC/$', views.helpPC, name='helpPC'), -+ url(r'^volunteer/$', views.volunteer, name='volunteer'), -+ - ) - - -diff --git a/webhub/views.py b/webhub/views.py -index 85a7077..b77b9ad 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -1436,6 +1436,14 @@ def change_pass_page(request): - def peacetrack(request): - return HttpResponse(jinja_environ.get_template('peacetrack.html').render({"pcuser":None})) - -+ -+ -+#Called when a user wants to see the details of a volunteer. -+def volunteer(request): -+ all_vol = Volunteer.objects.all() -+ return HttpResponse(jinja_environ.get_template('volunteer.html').render({"all_vol":all_posts, "pcuser":request.user.pcuser})) -+ -+ - #called when user wishes to go to the Peacetrack from dashboard - def aboutPC(request): - return HttpResponse(jinja_environ.get_template('aboutPC.html').render({"pcuser":None})) - -commit 6e2f073644501cd917b6464d6b3db42cf5624dc5 -Author: desaivaibhavi -Date: Mon Jul 14 07:16:53 2014 +0000 - - all apis added for the mobile team to interact with the webapp and database - -diff --git a/webhub/models.py b/webhub/models.py -index d53f418..7192e77 100644 ---- a/webhub/models.py -+++ b/webhub/models.py -@@ -211,7 +211,7 @@ class Output(models.Model): - def __unicode__(self): - return unicode(self.output_value) - --#ahithi baki -+ - class Outcome(models.Model): - #The sector with which the outcome is associated - outcome_sector = models.ForeignKey(Sector, null=False, related_name='outcome_sector') -@@ -225,13 +225,35 @@ class Outcome(models.Model): - def __unicode__(self): - return unicode(self.outcome_value) - -+ -+class Cohurt(models.Model): -+ #name -+ cohurt_name = models.CharField(max_length=300) -+ #short description -+ cohurt_desc = models.CharField(max_length=3000) -+ #no of members -+ cohurt_no_of_members = models.IntegerField() -+ #age range -+ cohurt_age = models.CharField(max_length=30) -+ #no of males -+ cohurt_males = models.IntegerField() -+ #no of females -+ cohurt_females = models.IntegerField() -+ #position within the community -+ cohurt_pos = models.CharField(max_length=30) -+ #other relevant notes -+ cohurt_notes = models.CharField(max_length=3000) -+ -+ def __unicode__(self): -+ return unicode(self.cohurt_name) -+ - class Activity(models.Model): - #title of the activity - activity_title = models.CharField(max_length=300) - #short description - activity_desc = models.CharField(max_length=3000) - #relevant cohurt name -- activity_cohurt = models.ForeignKey(Output, null=False, related_name='activity_cohurt') -+ activity_cohurt = models.ForeignKey(Cohurt, null=False, related_name='activity_cohurt') - #date & time of the activity creation - activity_created = models.DateTimeField(auto_now_add=True) - #output with which the activity is associated -@@ -255,26 +277,7 @@ class Measurement(models.Model): - def __unicode__(self): - return self.meas_title - --class Cohurt(models.Model): -- #name -- cohurt_name = models.CharField(max_length=300) -- #short description -- cohurt_desc = models.CharField(max_length=3000) -- #no of members -- cohurt_no_of_members = models.IntegerField() -- #age range -- cohurt_age = models.CharField(max_length=30) -- #no of males -- cohurt_males = models.IntegerField() -- #no of females -- cohurt_females = models.IntegerField() -- #position within the community -- cohurt_pos = models.CharField(max_length=30) -- #other relevant notes -- cohurt_notes = models.CharField(max_length=3000) -- -- def __unicode__(self): -- return self.id -+ - - class Volunteer(models.Model): - #username -diff --git a/webhub/models.pyc b/webhub/models.pyc -index f1d2dcf..58d2434 100644 -Binary files a/webhub/models.pyc and b/webhub/models.pyc differ -diff --git a/webhub/serializers.py b/webhub/serializers.py -index 1d9632d..855e348 100644 ---- a/webhub/serializers.py -+++ b/webhub/serializers.py -@@ -6,7 +6,7 @@ from rest_framework import serializers - class UserSerializer(serializers.HyperlinkedModelSerializer): - class Meta: - model = User -- fields = ('url', 'username', 'email') -+ fields = ('url', 'username', 'email','id') - - - class PcuserSerializer(serializers.ModelSerializer): -@@ -17,31 +17,31 @@ class PcuserSerializer(serializers.ModelSerializer): - class PostSerializer(serializers.ModelSerializer): - class Meta: - model = Post -- fields = ('owner', 'title_post', 'description_post', 'link_post', 'created','updated','id','image_post','imageobj_post') -+ fields = ('owner', 'title_post', 'description_post', 'link_post', 'created','updated','id','image_post','imageobj_post','id') - - - class RevPostSerializer(serializers.ModelSerializer): - class Meta: - model = RevPost -- fields = ('owner_rev_post', 'owner_rev', 'title_post_rev', 'description_post_rev', 'link_post_rev', 'created','id','title_change','description_change','link_change') -+ fields = ('owner_rev_post', 'owner_rev', 'title_post_rev', 'description_post_rev', 'link_post_rev', 'created','id','title_change','description_change','link_change','id') - - #Peacetrack begins here - - class RegionSerializer(serializers.ModelSerializer): - class Meta: - model = Region -- fields = ('region_name') -+ fields = ('region_name','id') - - - class SectorSerializer(serializers.ModelSerializer): - class Meta: - model = Sector -- fields = ('sector_name','sector_desc','sector_code') -+ fields = ('sector_name','sector_desc','sector_code','id') - - class PTPostSerializer(serializers.ModelSerializer): - class Meta: - model = PTPost -- fields = ('post_name','post_region','sector') -+ fields = ('post_name','post_region','sector','id') - - class ProjectSerializer(serializers.ModelSerializer): - class Meta: -@@ -51,45 +51,45 @@ class ProjectSerializer(serializers.ModelSerializer): - class GoalSerializer(serializers.ModelSerializer): - class Meta: - model = Goal -- fields = ('goal_name','goal_title','goal_stmt','goal_project') -+ fields = ('goal_name','goal_title','goal_stmt','goal_project','id') - - class ObjectiveSerializer(serializers.ModelSerializer): - class Meta: - model = Objective -- fields = ('obj_name','obj_title','obj_stmt','obj_goal') -+ fields = ('obj_name','obj_title','obj_stmt','obj_goal','id') - - class IndicatorSerializer(serializers.ModelSerializer): - class Meta: - model = Indicator -- fields = ('ind_obj','ind_type_1','ind_type_2') -+ fields = ('ind_obj','ind_type_1','ind_type_2','id') - - class OutputSerializer(serializers.ModelSerializer): - class Meta: - model = Output -- fields = ('output_sector','output_ptpost','output_ind','output_value') -+ fields = ('output_sector','output_ptpost','output_ind','output_value','id') - - - class OutcomeSerializer(serializers.ModelSerializer): - class Meta: - model = Outcome -- fields = ('outcome_sector','outcome_ptpost','outcome_ind','outcome_value') -+ fields = ('outcome_sector','outcome_ptpost','outcome_ind','outcome_value','id') - - class ActivitySerializer(serializers.ModelSerializer): - class Meta: - model = Activity -- fields = ('activity_title','activity_desc','activity_cohurt','activity_created','activity_output') -+ fields = ('activity_title','activity_desc','activity_cohurt','activity_created','activity_output','id') - - class MeasurementSerializer(serializers.ModelSerializer): - class Meta: - model = Measurement -- fields = ('meas_title','meas_desc','meas_cohurt','meas_created','meas_outcome') -+ fields = ('meas_title','meas_desc','meas_cohurt','meas_created','meas_outcome','id') - - class CohurtSerializer(serializers.ModelSerializer): - class Meta: - model = Cohurt -- fields = ('cohurt_name','cohurt_desc','cohurt_no_of_members','cohurt_age','cohurt_males','cohurt_females','cohurt_pos','cohurt_notes') -+ fields = ('cohurt_name','cohurt_desc','cohurt_no_of_members','cohurt_age','cohurt_males','cohurt_females','cohurt_pos','cohurt_notes','id') - - class VolunteerSerializer(serializers.ModelSerializer): - class Meta: - model = Volunteer -- fields = ('vol_name','vol_sector','vol_ptpost','vol_activity','vol_meas','vol_cohurt') -\ No newline at end of file -+ fields = ('vol_name','vol_sector','vol_ptpost','vol_activity','vol_meas','vol_cohurt','id') -\ No newline at end of file -diff --git a/webhub/serializers.pyc b/webhub/serializers.pyc -index 51b1e18..1ad5394 100644 -Binary files a/webhub/serializers.pyc and b/webhub/serializers.pyc differ -diff --git a/webhub/urls.py b/webhub/urls.py -index bb43d28..ace3d40 100644 ---- a/webhub/urls.py -+++ b/webhub/urls.py -@@ -10,6 +10,23 @@ from webhub import views - - router = routers.DefaultRouter() - router.register(r'users', views.UserViewSet) -+router.register(r'posts', views.PostViewSet) -+router.register(r'revposts', views.RevPostViewSet) -+router.register(r'regions', views.RegionViewSet) -+router.register(r'sectors', views.SectorViewSet) -+router.register(r'ptposts', views.PTPostViewSet) -+router.register(r'projects', views.ProjectViewSet) -+router.register(r'goals', views.GoalViewSet) -+router.register(r'objectives', views.ObjectiveViewSet) -+router.register(r'indicators', views.IndicatorViewSet) -+router.register(r'outputs', views.OutputViewSet) -+router.register(r'outcomes', views.OutcomeViewSet) -+router.register(r'activity', views.ActivityViewSet) -+router.register(r'measurement', views.MeasurementViewSet) -+router.register(r'cohurt', views.CohurtViewSet) -+router.register(r'volunteer', views.VolunteerViewSet) -+ -+ - - - -diff --git a/webhub/urls.pyc b/webhub/urls.pyc -index 4e010c8..d8e1bc3 100644 -Binary files a/webhub/urls.pyc and b/webhub/urls.pyc differ -diff --git a/webhub/views.py b/webhub/views.py -index 52e811f..85a7077 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -38,7 +38,7 @@ website = "http://192.168.33.10:8000" - - jinja_environ = jinja2.Environment(loader=jinja2.FileSystemLoader(['ui']), extensions=[loopcontrols]) - -- -+#apis for malaria begin here - class UserViewSet(viewsets.ModelViewSet): - """ - API endpoint that allows users to be viewed or edited. -@@ -85,6 +85,15 @@ def pcuser_detail(request, pk): - pcuser.delete() - return Response(status=status.HTTP_204_NO_CONTENT) - -+class PostViewSet(viewsets.ModelViewSet): -+ """ -+ API endpoint that allows users to be viewed or edited. -+ """ -+ queryset = Post.objects.all() -+ serializer_class = PostSerializer -+ -+ -+ - - #List all posts, or create a new post. - @api_view(['GET', 'POST']) -@@ -124,7 +133,13 @@ def post_detail(request, pk): - post.delete() - return Response(status=status.HTTP_204_NO_CONTENT) - -- -+ -+class RevPostViewSet(viewsets.ModelViewSet): -+ """ -+ API endpoint that allows users to be viewed or edited. -+ """ -+ queryset = RevPost.objects.all() -+ serializer_class = RevPostSerializer - - #List all revision of a posts - @api_view(['GET', 'POST']) -@@ -164,8 +179,635 @@ def revpost_detail(request, pk): - revpost.delete() - return Response(status=status.HTTP_204_NO_CONTENT) - -+#apis for malaria end here -+ -+#apis for peacetrack begin here -+ -+#for regions -+class RegionViewSet(viewsets.ModelViewSet): -+ """ -+ API endpoint that allows users to be viewed or edited. -+ """ -+ queryset = Region.objects.all() -+ serializer_class = RegionSerializer -+ -+#List all region -+@api_view(['GET', 'POST']) -+def region_list(request): -+ if request.method == 'GET': -+ region = Region.objects.all() -+ serializer = RegionSerializer(region, many=True) -+ return Response(serializer.data) -+ -+ elif request.method == 'POST': -+ serializer = RegionSerializer(data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data, status=status.HTTP_201_CREATED) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+#Retrieve, update or delete a region instance. -+@api_view(['GET', 'PUT', 'DELETE']) -+def region_detail(request, pk): -+ try: -+ region = Region.objects.get(pk=pk) -+ except Pcuser.DoesNotExist: -+ return Response(status=status.HTTP_404_NOT_FOUND) -+ -+ if request.method == 'GET': -+ serializer = RegionSerializer(region) -+ return Response(serializer.data) -+ -+ elif request.method == 'PUT': -+ serializer = RegionSerializer(post, data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+ elif request.method == 'DELETE': -+ region.delete() -+ return Response(status=status.HTTP_204_NO_CONTENT) -+ -+ -+ -+#for sectors -+class SectorViewSet(viewsets.ModelViewSet): -+ """ -+ API endpoint that allows users to be viewed or edited. -+ """ -+ queryset = Sector.objects.all() -+ serializer_class = SectorSerializer -+ -+#List all sectors -+@api_view(['GET', 'POST']) -+def sector_list(request): -+ if request.method == 'GET': -+ sector = Sector.objects.all() -+ serializer = SectorSerializer(sector, many=True) -+ return Response(serializer.data) -+ -+ elif request.method == 'POST': -+ serializer = SectorSerializer(data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data, status=status.HTTP_201_CREATED) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+#Retrieve, update or delete a sector instance. -+@api_view(['GET', 'PUT', 'DELETE']) -+def sector_detail(request, pk): -+ try: -+ sector = Sector.objects.get(pk=pk) -+ except Pcuser.DoesNotExist: -+ return Response(status=status.HTTP_404_NOT_FOUND) -+ -+ if request.method == 'GET': -+ serializer = SectorSerializer(sector) -+ return Response(serializer.data) -+ -+ elif request.method == 'PUT': -+ serializer = SectorSerializer(post, data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+ elif request.method == 'DELETE': -+ sector.delete() -+ return Response(status=status.HTTP_204_NO_CONTENT) - - -+#for ptposts -+class PTPostViewSet(viewsets.ModelViewSet): -+ """ -+ API endpoint that allows users to be viewed or edited. -+ """ -+ queryset = PTPost.objects.all() -+ serializer_class = PTPostSerializer -+ -+#List all ptpost -+@api_view(['GET', 'POST']) -+def ptpost_list(request): -+ if request.method == 'GET': -+ ptpost = PTPost.objects.all() -+ serializer = PTPostSerializer(ptpost, many=True) -+ return Response(serializer.data) -+ -+ elif request.method == 'POST': -+ serializer = PTPostSerializer(data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data, status=status.HTTP_201_CREATED) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+#Retrieve, update or delete a ptpost instance. -+@api_view(['GET', 'PUT', 'DELETE']) -+def ptpost_detail(request, pk): -+ try: -+ ptpost = PTPost.objects.get(pk=pk) -+ except Pcuser.DoesNotExist: -+ return Response(status=status.HTTP_404_NOT_FOUND) -+ -+ if request.method == 'GET': -+ serializer = PTPostSerializer(ptpost) -+ return Response(serializer.data) -+ -+ elif request.method == 'PUT': -+ serializer = PTPostSerializer(post, data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+ elif request.method == 'DELETE': -+ ptpost.delete() -+ return Response(status=status.HTTP_204_NO_CONTENT) -+ -+#error -+#for projects -+class ProjectViewSet(viewsets.ModelViewSet): -+ """ -+ API endpoint that allows users to be viewed or edited. -+ """ -+ queryset = Project.objects.all() -+ serializer_class = ProjectSerializer -+ -+#List all projects -+@api_view(['GET', 'POST']) -+def project_list(request): -+ if request.method == 'GET': -+ project = Project.objects.all() -+ serializer = ProjectSerializer(project, many=True) -+ return Response(serializer.data) -+ -+ elif request.method == 'POST': -+ serializer = ProjectSerializer(data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data, status=status.HTTP_201_CREATED) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+#Retrieve, update or delete a project instance. -+@api_view(['GET', 'PUT', 'DELETE']) -+def project_detail(request, pk): -+ try: -+ project = Project.objects.get(pk=pk) -+ except Pcuser.DoesNotExist: -+ return Response(status=status.HTTP_404_NOT_FOUND) -+ -+ if request.method == 'GET': -+ serializer = ProjectSerializer(project) -+ return Response(serializer.data) -+ -+ elif request.method == 'PUT': -+ serializer = ProjectSerializer(project, data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+ elif request.method == 'DELETE': -+ project.delete() -+ return Response(status=status.HTTP_204_NO_CONTENT) -+ -+ -+#for goals -+class GoalViewSet(viewsets.ModelViewSet): -+ """ -+ API endpoint that allows users to be viewed or edited. -+ """ -+ queryset = Goal.objects.all() -+ serializer_class = GoalSerializer -+ -+#List all goal -+@api_view(['GET', 'POST']) -+def goal_list(request): -+ if request.method == 'GET': -+ goal = Goal.objects.all() -+ serializer = GoalSerializer(goal, many=True) -+ return Response(serializer.data) -+ -+ elif request.method == 'POST': -+ serializer = GoalSerializer(data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data, status=status.HTTP_201_CREATED) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+#Retrieve, update or delete a goal instance. -+@api_view(['GET', 'PUT', 'DELETE']) -+def goal_detail(request, pk): -+ try: -+ goal = Goal.objects.get(pk=pk) -+ except Pcuser.DoesNotExist: -+ return Response(status=status.HTTP_404_NOT_FOUND) -+ -+ if request.method == 'GET': -+ serializer = GoalSerializer(goal) -+ return Response(serializer.data) -+ -+ elif request.method == 'PUT': -+ serializer = GoalSerializer(goal, data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+ elif request.method == 'DELETE': -+ goal.delete() -+ return Response(status=status.HTTP_204_NO_CONTENT) -+ -+#for objectives -+class ObjectiveViewSet(viewsets.ModelViewSet): -+ """ -+ API endpoint that allows users to be viewed or edited. -+ """ -+ queryset = Objective.objects.all() -+ serializer_class = ObjectiveSerializer -+ -+#List all objective -+@api_view(['GET', 'POST']) -+def objective_list(request): -+ if request.method == 'GET': -+ objective = Objective.objects.all() -+ serializer = ObjectiveSerializer(objective, many=True) -+ return Response(serializer.data) -+ -+ elif request.method == 'POST': -+ serializer = ObjectiveSerializer(data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data, status=status.HTTP_201_CREATED) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+#Retrieve, update or delete a objective instance. -+@api_view(['GET', 'PUT', 'DELETE']) -+def objective_detail(request, pk): -+ try: -+ objective = Objective.objects.get(pk=pk) -+ except Pcuser.DoesNotExist: -+ return Response(status=status.HTTP_404_NOT_FOUND) -+ -+ if request.method == 'GET': -+ serializer = ObjectiveSerializer(objective) -+ return Response(serializer.data) -+ -+ elif request.method == 'PUT': -+ serializer = ObjectiveSerializer(objective, data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+ elif request.method == 'DELETE': -+ objective.delete() -+ return Response(status=status.HTTP_204_NO_CONTENT) -+ -+ -+#for indicators -+class IndicatorViewSet(viewsets.ModelViewSet): -+ """ -+ API endpoint that allows users to be viewed or edited. -+ """ -+ queryset = Indicator.objects.all() -+ serializer_class = IndicatorSerializer -+ -+#List all indicator -+@api_view(['GET', 'POST']) -+def indicator_list(request): -+ if request.method == 'GET': -+ indicator = Indicator.objects.all() -+ serializer = IndicatorSerializer(indicator, many=True) -+ return Response(serializer.data) -+ -+ elif request.method == 'POST': -+ serializer = IndicatorSerializer(data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data, status=status.HTTP_201_CREATED) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+#Retrieve, update or delete a indicator instance. -+@api_view(['GET', 'PUT', 'DELETE']) -+def indicator_detail(request, pk): -+ try: -+ indicator = Indicator.objects.get(pk=pk) -+ except Pcuser.DoesNotExist: -+ return Response(status=status.HTTP_404_NOT_FOUND) -+ -+ if request.method == 'GET': -+ serializer = IndicatorSerializer(indicator) -+ return Response(serializer.data) -+ -+ elif request.method == 'PUT': -+ serializer = IndicatorSerializer(indicator, data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+ elif request.method == 'DELETE': -+ indicator.delete() -+ return Response(status=status.HTTP_204_NO_CONTENT) -+ -+ -+ -+#for outputs -+class OutputViewSet(viewsets.ModelViewSet): -+ """ -+ API endpoint that allows users to be viewed or edited. -+ """ -+ queryset = Output.objects.all() -+ serializer_class = OutputSerializer -+ -+#List all output -+@api_view(['GET', 'POST']) -+def output_list(request): -+ if request.method == 'GET': -+ output = Output.objects.all() -+ serializer = OutputSerializer(output, many=True) -+ return Response(serializer.data) -+ -+ elif request.method == 'POST': -+ serializer = OutputSerializer(data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data, status=status.HTTP_201_CREATED) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+#Retrieve, update or delete a output instance. -+@api_view(['GET', 'PUT', 'DELETE']) -+def output_detail(request, pk): -+ try: -+ output = Output.objects.get(pk=pk) -+ except Pcuser.DoesNotExist: -+ return Response(status=status.HTTP_404_NOT_FOUND) -+ -+ if request.method == 'GET': -+ serializer = OutputSerializer(output) -+ return Response(serializer.data) -+ -+ elif request.method == 'PUT': -+ serializer = OutputSerializer(output, data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+ elif request.method == 'DELETE': -+ output.delete() -+ return Response(status=status.HTTP_204_NO_CONTENT) -+ -+ -+#for outcomes -+class OutcomeViewSet(viewsets.ModelViewSet): -+ """ -+ API endpoint that allows users to be viewed or edited. -+ """ -+ queryset = Outcome.objects.all() -+ serializer_class = OutcomeSerializer -+ -+#List all outcome -+@api_view(['GET', 'POST']) -+def outcome_list(request): -+ if request.method == 'GET': -+ outcome = Outcome.objects.all() -+ serializer = OutcomeSerializer(outcome, many=True) -+ return Response(serializer.data) -+ -+ elif request.method == 'POST': -+ serializer = OutcomeSerializer(data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data, status=status.HTTP_201_CREATED) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+#Retrieve, update or delete a outcome instance. -+@api_view(['GET', 'PUT', 'DELETE']) -+def outcome_detail(request, pk): -+ try: -+ outcome = Outcome.objects.get(pk=pk) -+ except Pcuser.DoesNotExist: -+ return Response(status=status.HTTP_404_NOT_FOUND) -+ -+ if request.method == 'GET': -+ serializer = OutcomeSerializer(outcome) -+ return Response(serializer.data) -+ -+ elif request.method == 'PUT': -+ serializer = OutcomeSerializer(outcome, data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+ elif request.method == 'DELETE': -+ outcome.delete() -+ return Response(status=status.HTTP_204_NO_CONTENT) -+ -+ -+ -+#for activitys -+class ActivityViewSet(viewsets.ModelViewSet): -+ """ -+ API endpoint that allows users to be viewed or edited. -+ """ -+ queryset = Activity.objects.all() -+ serializer_class = ActivitySerializer -+ -+#List all activity -+@api_view(['GET', 'POST']) -+def activity_list(request): -+ if request.method == 'GET': -+ activity = Activity.objects.all() -+ serializer = ActivitySerializer(activity, many=True) -+ return Response(serializer.data) -+ -+ elif request.method == 'POST': -+ serializer = ActivitySerializer(data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data, status=status.HTTP_201_CREATED) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+#Retrieve, update or delete a activity instance. -+@api_view(['GET', 'PUT', 'DELETE']) -+def activity_detail(request, pk): -+ try: -+ activity = Activity.objects.get(pk=pk) -+ except Pcuser.DoesNotExist: -+ return Response(status=status.HTTP_404_NOT_FOUND) -+ -+ if request.method == 'GET': -+ serializer = ActivitySerializer(activity) -+ return Response(serializer.data) -+ -+ elif request.method == 'PUT': -+ serializer = ActivitySerializer(activity, data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+ elif request.method == 'DELETE': -+ activity.delete() -+ return Response(status=status.HTTP_204_NO_CONTENT) -+ -+ -+#for measurements -+class MeasurementViewSet(viewsets.ModelViewSet): -+ """ -+ API endpoint that allows users to be viewed or edited. -+ """ -+ queryset = Measurement.objects.all() -+ serializer_class = MeasurementSerializer -+ -+#List all measurement -+@api_view(['GET', 'POST']) -+def measurement_list(request): -+ if request.method == 'GET': -+ measurement = Measurement.objects.all() -+ serializer = MeasurementSerializer(measurement, many=True) -+ return Response(serializer.data) -+ -+ elif request.method == 'POST': -+ serializer = MeasurementSerializer(data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data, status=status.HTTP_201_CREATED) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+#Retrieve, update or delete a measurement instance. -+@api_view(['GET', 'PUT', 'DELETE']) -+def measurement_detail(request, pk): -+ try: -+ measurement = Measurement.objects.get(pk=pk) -+ except Pcuser.DoesNotExist: -+ return Response(status=status.HTTP_404_NOT_FOUND) -+ -+ if request.method == 'GET': -+ serializer = MeasurementSerializer(measurement) -+ return Response(serializer.data) -+ -+ elif request.method == 'PUT': -+ serializer = MeasurementSerializer(measurement, data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+ elif request.method == 'DELETE': -+ measurement.delete() -+ return Response(status=status.HTTP_204_NO_CONTENT) -+ -+ -+ -+#for cohurts -+class CohurtViewSet(viewsets.ModelViewSet): -+ """ -+ API endpoint that allows users to be viewed or edited. -+ """ -+ queryset = Cohurt.objects.all() -+ serializer_class = CohurtSerializer -+ -+#List all cohurt -+@api_view(['GET', 'POST']) -+def cohurt_list(request): -+ if request.method == 'GET': -+ cohurt = Cohurt.objects.all() -+ serializer = CohurtSerializer(cohurt, many=True) -+ return Response(serializer.data) -+ -+ elif request.method == 'POST': -+ serializer = CohurtSerializer(data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data, status=status.HTTP_201_CREATED) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+#Retrieve, update or delete a cohurt instance. -+@api_view(['GET', 'PUT', 'DELETE']) -+def cohurt_detail(request, pk): -+ try: -+ cohurt = Cohurt.objects.get(pk=pk) -+ except Pcuser.DoesNotExist: -+ return Response(status=status.HTTP_404_NOT_FOUND) -+ -+ if request.method == 'GET': -+ serializer = CohurtSerializer(cohurt) -+ return Response(serializer.data) -+ -+ elif request.method == 'PUT': -+ serializer = CohurtSerializer(cohurt, data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+ elif request.method == 'DELETE': -+ cohurt.delete() -+ return Response(status=status.HTTP_204_NO_CONTENT) -+ -+ -+ -+#for volunteers -+class VolunteerViewSet(viewsets.ModelViewSet): -+ """ -+ API endpoint that allows users to be viewed or edited. -+ """ -+ queryset = Volunteer.objects.all() -+ serializer_class = VolunteerSerializer -+ -+#List all volunteer -+@api_view(['GET', 'POST']) -+def volunteer_list(request): -+ if request.method == 'GET': -+ volunteer = Volunteer.objects.all() -+ serializer = VolunteerSerializer(volunteer, many=True) -+ return Response(serializer.data) -+ -+ elif request.method == 'POST': -+ serializer = VolunteerSerializer(data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data, status=status.HTTP_201_CREATED) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+#Retrieve, update or delete a volunteer instance. -+@api_view(['GET', 'PUT', 'DELETE']) -+def volunteer_detail(request, pk): -+ try: -+ volunteer = Volunteer.objects.get(pk=pk) -+ except Pcuser.DoesNotExist: -+ return Response(status=status.HTTP_404_NOT_FOUND) -+ -+ if request.method == 'GET': -+ serializer = VolunteerSerializer(volunteer) -+ return Response(serializer.data) -+ -+ elif request.method == 'PUT': -+ serializer = VolunteerSerializer(volunteer, data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+ elif request.method == 'DELETE': -+ volunteer.delete() -+ return Response(status=status.HTTP_204_NO_CONTENT) -+ -+ -+ -+#apis for peacetrack end here -+ -+ -+ -+ -+ -+ -+ -+ - - - #Calls index page -diff --git a/webhub/views.pyc b/webhub/views.pyc -index 38e1265..ee2eefc 100644 -Binary files a/webhub/views.pyc and b/webhub/views.pyc differ - -commit 25c1b73c36f88bccef1501edcbed682cfb047b4c -Author: desaivaibhavi -Date: Wed Jul 9 10:34:35 2014 +0000 - - apis start for peacetrack - -diff --git a/ui/peacetrack.html b/ui/peacetrack.html -index f561a87..38733d8 100644 ---- a/ui/peacetrack.html -+++ b/ui/peacetrack.html -@@ -13,7 +13,11 @@ email : ranihaileydesai@gmail.com - - {% include "header.html" %} -





--

Here the information about peacetrack would be shown

-+
-+

Summary

-+

Volunteer

-+

Graph

-+
- -

















- {% include "footer.html" %} -diff --git a/webhub/models.py b/webhub/models.py -index 31c47f5..d53f418 100644 ---- a/webhub/models.py -+++ b/webhub/models.py -@@ -173,28 +173,28 @@ class Objective(models.Model): - #Statement of the objective - obj_stmt = models.CharField(max_length=3000) - #The goal with which the objective is associated -- obj_goal = models.ForeignKey(Region, null=False, related_name='obj_goal') -+ obj_goal = models.ForeignKey(Goal, null=False, related_name='obj_goal') - - def __unicode__(self): - return self.obj_name - - class Indicator(models.Model): - #The objective with which the indicator is associated -- ind_obj = models.ForeignKey(Region, null=False, related_name='ind_obj') -+ ind_obj = models.ForeignKey(Objective, null=False, related_name='ind_obj') - #Indicator description - #Indicator type (SI/PDI/SO/PD) - #0 - SI - #1 - PDI - #2 - SO - #3 - PD -- ind_type_1 = models.CharField(max_length="20", default="None", null=False) -+ ind_type_1 = models.CharField(max_length="100", default="None", null=False) - #Indicator type (Outcome/Output) - #true - Outcome - #false - Output - ind_type_2 = models.BooleanField(default=True) - - def __unicode__(self): -- return self.id -+ return self.ind_type_1 - - - -@@ -209,9 +209,9 @@ class Output(models.Model): - output_value = models.IntegerField() - - def __unicode__(self): -- return self.option_value -+ return unicode(self.output_value) - -- -+#ahithi baki - class Outcome(models.Model): - #The sector with which the outcome is associated - outcome_sector = models.ForeignKey(Sector, null=False, related_name='outcome_sector') -@@ -223,7 +223,7 @@ class Outcome(models.Model): - outcome_value = models.IntegerField() - - def __unicode__(self): -- return self.outcome_value -+ return unicode(self.outcome_value) - - class Activity(models.Model): - #title of the activity -diff --git a/webhub/models.pyc b/webhub/models.pyc -index 199672a..f1d2dcf 100644 -Binary files a/webhub/models.pyc and b/webhub/models.pyc differ -diff --git a/webhub/serializers.py b/webhub/serializers.py -index cb2eecb..1d9632d 100644 ---- a/webhub/serializers.py -+++ b/webhub/serializers.py -@@ -25,6 +25,71 @@ class RevPostSerializer(serializers.ModelSerializer): - model = RevPost - fields = ('owner_rev_post', 'owner_rev', 'title_post_rev', 'description_post_rev', 'link_post_rev', 'created','id','title_change','description_change','link_change') - -+#Peacetrack begins here - -+class RegionSerializer(serializers.ModelSerializer): -+ class Meta: -+ model = Region -+ fields = ('region_name') -+ -+ -+class SectorSerializer(serializers.ModelSerializer): -+ class Meta: -+ model = Sector -+ fields = ('sector_name','sector_desc','sector_code') -+ -+class PTPostSerializer(serializers.ModelSerializer): -+ class Meta: -+ model = PTPost -+ fields = ('post_name','post_region','sector') -+ -+class ProjectSerializer(serializers.ModelSerializer): -+ class Meta: -+ model = Project -+ fields = ('project_name','project_purpose','project_sector') -+ -+class GoalSerializer(serializers.ModelSerializer): -+ class Meta: -+ model = Goal -+ fields = ('goal_name','goal_title','goal_stmt','goal_project') -+ -+class ObjectiveSerializer(serializers.ModelSerializer): -+ class Meta: -+ model = Objective -+ fields = ('obj_name','obj_title','obj_stmt','obj_goal') -+ -+class IndicatorSerializer(serializers.ModelSerializer): -+ class Meta: -+ model = Indicator -+ fields = ('ind_obj','ind_type_1','ind_type_2') -+ -+class OutputSerializer(serializers.ModelSerializer): -+ class Meta: -+ model = Output -+ fields = ('output_sector','output_ptpost','output_ind','output_value') -+ -+ -+class OutcomeSerializer(serializers.ModelSerializer): -+ class Meta: -+ model = Outcome -+ fields = ('outcome_sector','outcome_ptpost','outcome_ind','outcome_value') -+ -+class ActivitySerializer(serializers.ModelSerializer): -+ class Meta: -+ model = Activity -+ fields = ('activity_title','activity_desc','activity_cohurt','activity_created','activity_output') - -- -\ No newline at end of file -+class MeasurementSerializer(serializers.ModelSerializer): -+ class Meta: -+ model = Measurement -+ fields = ('meas_title','meas_desc','meas_cohurt','meas_created','meas_outcome') -+ -+class CohurtSerializer(serializers.ModelSerializer): -+ class Meta: -+ model = Cohurt -+ fields = ('cohurt_name','cohurt_desc','cohurt_no_of_members','cohurt_age','cohurt_males','cohurt_females','cohurt_pos','cohurt_notes') -+ -+class VolunteerSerializer(serializers.ModelSerializer): -+ class Meta: -+ model = Volunteer -+ fields = ('vol_name','vol_sector','vol_ptpost','vol_activity','vol_meas','vol_cohurt') -\ No newline at end of file - -commit d1dea7765398b90a17cc1b3245b84c05cdeeee62 -Author: desaivaibhavi -Date: Sun Jul 6 20:39:24 2014 +0000 - - summary and volunteer added - -diff --git a/ui/summary.html b/ui/summary.html -new file mode 100644 -index 0000000..793065e ---- /dev/null -+++ b/ui/summary.html -@@ -0,0 +1,8 @@ -+ -+ -+ -\ No newline at end of file -diff --git a/ui/volunteer.html b/ui/volunteer.html -new file mode 100644 -index 0000000..5a8361e ---- /dev/null -+++ b/ui/volunteer.html -@@ -0,0 +1,8 @@ -+ -+ -+ -\ No newline at end of file -diff --git a/webhub/admin.py b/webhub/admin.py -index 6163a44..a84c56a 100644 ---- a/webhub/admin.py -+++ b/webhub/admin.py -@@ -5,10 +5,26 @@ - - - from django.contrib import admin --from webhub.models import Pcuser --from webhub.models import Post -+from webhub.models import * -+ - - admin.site.register(Pcuser) - admin.site.register(Post) -+admin.site.register(RevPost) -+admin.site.register(Region) -+admin.site.register(Sector) -+admin.site.register(PTPost) -+admin.site.register(Project) -+admin.site.register(Goal) -+admin.site.register(Objective) -+admin.site.register(Indicator) -+admin.site.register(Output) -+admin.site.register(Outcome) -+admin.site.register(Activity) -+admin.site.register(Measurement) -+admin.site.register(Cohurt) -+admin.site.register(Volunteer) -+ -+ - - # Register your models here. -diff --git a/webhub/admin.pyc b/webhub/admin.pyc -index 95dc157..216f3e0 100644 -Binary files a/webhub/admin.pyc and b/webhub/admin.pyc differ - -commit efd1df5a11d4d9614e3b1b4a67a0daae0776c915 -Author: desaivaibhavi -Date: Thu Jul 3 21:58:26 2014 +0000 - - software design doc added - -diff --git a/docs/SoftwareDesignDocument.pdf b/docs/SoftwareDesignDocument.pdf -new file mode 100644 -index 0000000..1f026b8 -Binary files /dev/null and b/docs/SoftwareDesignDocument.pdf differ - -commit 5897e134698fc7b3d5e874924923a4dededdc3bf -Author: desaivaibhavi -Date: Thu Jul 3 21:17:19 2014 +0000 - - basic database design for peacetrack added - -diff --git a/webhub/models.py b/webhub/models.py -index a22d034..31c47f5 100644 ---- a/webhub/models.py -+++ b/webhub/models.py -@@ -107,3 +107,191 @@ class RevPost(models.Model): - - def __unicode__(self): - return self.owner_rev.user.username -+ -+ -+#Peacetrack begins here -+ -+class Region(models.Model): -+ #Name of the region -+ region_name = models.CharField(max_length=300) -+ -+ def __unicode__(self): -+ return self.region_name -+ -+class Sector(models.Model): -+ #Name of the sector -+ sector_name = models.CharField(max_length=300) -+ #Description of the sector -+ sector_desc = models.CharField(max_length=3000) -+ #Code of the sector -+ sector_code = models.CharField(max_length=300) -+ -+ def __unicode__(self): -+ return self.sector_name -+ -+ -+class PTPost(models.Model): -+ #Name of the post -+ post_name = models.CharField(max_length=300) -+ #The region with which the post is associated -+ post_region = models.ForeignKey(Region, null=False, related_name='post_region') -+ #many to many relationship with the Sector -+ sector = models.ManyToManyField(Sector) -+ -+ def __unicode__(self): -+ return self.post_name -+ -+class Project(models.Model): -+ #Name of the project -+ project_name = models.CharField(max_length=300) -+ #Purpose of the project -+ project_purpose = models.CharField(max_length=3000) -+ #The sector with which the project is associated -+ project_sector = models.OneToOneField(Sector, primary_key=True) -+ -+ def __unicode__(self): -+ return self.project_name -+ -+class Goal(models.Model): -+ #Name of the goal -+ goal_name = models.CharField(max_length=300) -+ #Title of the goal -+ goal_title = models.CharField(max_length=1000) -+ #Statement of the goal -+ goal_stmt = models.CharField(max_length=3000) -+ #The project with which the goal is associated -+ goal_project = models.ForeignKey(Region, null=False, related_name='goal_project') -+ -+ def __unicode__(self): -+ return self.goal_name -+ -+class Objective(models.Model): -+ #Name of the objective -+ obj_name = models.CharField(max_length=300) -+ #Title of the objective -+ obj_title = models.CharField(max_length=1000) -+ #Statement of the objective -+ obj_stmt = models.CharField(max_length=3000) -+ #The goal with which the objective is associated -+ obj_goal = models.ForeignKey(Region, null=False, related_name='obj_goal') -+ -+ def __unicode__(self): -+ return self.obj_name -+ -+class Indicator(models.Model): -+ #The objective with which the indicator is associated -+ ind_obj = models.ForeignKey(Region, null=False, related_name='ind_obj') -+ #Indicator description -+ #Indicator type (SI/PDI/SO/PD) -+ #0 - SI -+ #1 - PDI -+ #2 - SO -+ #3 - PD -+ ind_type_1 = models.CharField(max_length="20", default="None", null=False) -+ #Indicator type (Outcome/Output) -+ #true - Outcome -+ #false - Output -+ ind_type_2 = models.BooleanField(default=True) -+ -+ def __unicode__(self): -+ return self.id -+ -+ -+ -+class Output(models.Model): -+ #The sector with which the output is associated -+ output_sector = models.ForeignKey(Sector, null=False, related_name='output_sector') -+ #The country(post) with which the output is associated -+ output_ptpost= models.ForeignKey(PTPost, null=False, related_name='output_ptpost') -+ #The indicator with which the output is associated -+ output_ind= models.ForeignKey(Indicator, null=False, related_name='output_ind') -+ #integer (the output) -+ output_value = models.IntegerField() -+ -+ def __unicode__(self): -+ return self.option_value -+ -+ -+class Outcome(models.Model): -+ #The sector with which the outcome is associated -+ outcome_sector = models.ForeignKey(Sector, null=False, related_name='outcome_sector') -+ #The country(post) with which the outcome is associated -+ outcome_ptpost= models.ForeignKey(PTPost, null=False, related_name='outcome_ptpost') -+ #The indicator with which the outcome is associated -+ outcome_ind= models.ForeignKey(Indicator, null=False, related_name='outcome_ind') -+ #integer (the outcome) -+ outcome_value = models.IntegerField() -+ -+ def __unicode__(self): -+ return self.outcome_value -+ -+class Activity(models.Model): -+ #title of the activity -+ activity_title = models.CharField(max_length=300) -+ #short description -+ activity_desc = models.CharField(max_length=3000) -+ #relevant cohurt name -+ activity_cohurt = models.ForeignKey(Output, null=False, related_name='activity_cohurt') -+ #date & time of the activity creation -+ activity_created = models.DateTimeField(auto_now_add=True) -+ #output with which the activity is associated -+ activity_output = models.ForeignKey(Output, null=False, related_name='activity_output') -+ -+ def __unicode__(self): -+ return self.activity_title -+ -+class Measurement(models.Model): -+ #title of the Measurement -+ meas_title = models.CharField(max_length=300) -+ #short description of the Measurement -+ meas_desc = models.CharField(max_length=3000) -+ #relevant cohurt name -+ meas_cohurt = models.ForeignKey(Output, null=False, related_name='meas_cohurt') -+ #date & time of the Measurement creation -+ meas_created = models.DateTimeField(auto_now_add=True) -+ #outcome with which the Measurement is associated -+ meas_outcome = models.ForeignKey(Outcome, null=False, related_name='meas_outcome') -+ -+ def __unicode__(self): -+ return self.meas_title -+ -+class Cohurt(models.Model): -+ #name -+ cohurt_name = models.CharField(max_length=300) -+ #short description -+ cohurt_desc = models.CharField(max_length=3000) -+ #no of members -+ cohurt_no_of_members = models.IntegerField() -+ #age range -+ cohurt_age = models.CharField(max_length=30) -+ #no of males -+ cohurt_males = models.IntegerField() -+ #no of females -+ cohurt_females = models.IntegerField() -+ #position within the community -+ cohurt_pos = models.CharField(max_length=30) -+ #other relevant notes -+ cohurt_notes = models.CharField(max_length=3000) -+ -+ def __unicode__(self): -+ return self.id -+ -+class Volunteer(models.Model): -+ #username -+ vol_name = models.CharField(max_length=300) -+ #password -+ -+ #sector -+ vol_sector = models.ForeignKey(Sector, null=False, related_name='vol_sector') -+ #country -+ vol_ptpost = models.ForeignKey(PTPost, null=False, related_name='vol_ptpost') -+ #activity -+ vol_activity = models.ManyToManyField(Activity) -+ #measurement -+ vol_meas = models.ManyToManyField(Measurement) -+ #cohurt -+ vol_cohurt = models.ManyToManyField(Cohurt) -+ -+ def __unicode__(self): -+ return self.vol_name -+ -diff --git a/webhub/models.pyc b/webhub/models.pyc -index 4af9dd2..199672a 100644 -Binary files a/webhub/models.pyc and b/webhub/models.pyc differ - -commit 68446efeb49a1285fdf600b704b1cecb877522a7 -Author: desaivaibhavi -Date: Tue Jun 24 06:52:31 2014 +0000 - - api work done - -diff --git a/webhub/serializers.py b/webhub/serializers.py -index 4dddc6a..cb2eecb 100644 ---- a/webhub/serializers.py -+++ b/webhub/serializers.py -@@ -17,4 +17,14 @@ class PcuserSerializer(serializers.ModelSerializer): - class PostSerializer(serializers.ModelSerializer): - class Meta: - model = Post -- fields = ('owner', 'title_post', 'description_post', 'created','updated','id') -\ No newline at end of file -+ fields = ('owner', 'title_post', 'description_post', 'link_post', 'created','updated','id','image_post','imageobj_post') -+ -+ -+class RevPostSerializer(serializers.ModelSerializer): -+ class Meta: -+ model = RevPost -+ fields = ('owner_rev_post', 'owner_rev', 'title_post_rev', 'description_post_rev', 'link_post_rev', 'created','id','title_change','description_change','link_change') -+ -+ -+ -+ -\ No newline at end of file -diff --git a/webhub/serializers.pyc b/webhub/serializers.pyc -index c8f09ba..51b1e18 100644 -Binary files a/webhub/serializers.pyc and b/webhub/serializers.pyc differ -diff --git a/webhub/urls.py b/webhub/urls.py -index d9c9dd1..bb43d28 100644 ---- a/webhub/urls.py -+++ b/webhub/urls.py -@@ -41,8 +41,10 @@ urlpatterns = patterns('', - url(r'^change_pass_page/$', views.change_pass_page, name='change_pass_page'), - url(r'^pcuser/$', views.pcuser_list, name='pcuser_list'), - url(r'^post/$', views.post_list, name='post_list'), -+ url(r'^revpost/$', views.revpost_list, name='revpost_list'), - url(r'^pcuser/(?P[0-9]+)/$', views.pcuser_detail, name='pcuser_detail'), - url(r'^post/(?P[0-9]+)/$', views.post_detail, name='post_detail'), -+ url(r'^revpost/(?P[0-9]+)/$', views.revpost_detail, name='revpost_detail'), - url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), - url(r'^api/', include(router.urls)), - url(r'^aboutPC/$', views.aboutPC, name='aboutPC'), -diff --git a/webhub/urls.pyc b/webhub/urls.pyc -index 73b49f9..4e010c8 100644 -Binary files a/webhub/urls.pyc and b/webhub/urls.pyc differ -diff --git a/webhub/views.py b/webhub/views.py -index a965b5f..52e811f 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -124,6 +124,48 @@ def post_detail(request, pk): - post.delete() - return Response(status=status.HTTP_204_NO_CONTENT) - -+ -+ -+#List all revision of a posts -+@api_view(['GET', 'POST']) -+def revpost_list(request): -+ if request.method == 'GET': -+ revpost = RevPost.objects.all() -+ serializer = RevPostSerializer(revpost, many=True) -+ return Response(serializer.data) -+ -+ elif request.method == 'POST': -+ serializer = RevPostSerializer(data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data, status=status.HTTP_201_CREATED) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+#Retrieve, update or delete a revpost instance. -+@api_view(['GET', 'PUT', 'DELETE']) -+def revpost_detail(request, pk): -+ try: -+ revpost = RevPost.objects.get(pk=pk) -+ except Pcuser.DoesNotExist: -+ return Response(status=status.HTTP_404_NOT_FOUND) -+ -+ if request.method == 'GET': -+ serializer = RevPostSerializer(post) -+ return Response(serializer.data) -+ -+ elif request.method == 'PUT': -+ serializer = RevPostSerializer(post, data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+ elif request.method == 'DELETE': -+ revpost.delete() -+ return Response(status=status.HTTP_204_NO_CONTENT) -+ -+ -+ - - - #Calls index page -diff --git a/webhub/views.pyc b/webhub/views.pyc -index 84e3031..38e1265 100644 -Binary files a/webhub/views.pyc and b/webhub/views.pyc differ - -commit 70dfb736b8e0aa312fccdf962c37f80ad14b8744 -Author: desaivaibhavi -Date: Tue Jun 24 06:21:49 2014 +0000 - - image field added in post - -diff --git a/ui/newpost.html b/ui/newpost.html -index 8d62dc1..b282afc 100644 ---- a/ui/newpost.html -+++ b/ui/newpost.html -@@ -15,7 +15,7 @@ email : ranihaileydesai@gmail.com -





-

Malaria : infoHub

- --
-+
-
-

New Post

-
-@@ -40,7 +40,6 @@ email : ranihaileydesai@gmail.com -
-
- -- -
-
-
-@@ -55,16 +54,19 @@ email : ranihaileydesai@gmail.com - - - -+
-+
-+
-+
-+
-+

Add image

-+
-+
-+ -+
-+
-
-- -- --
-- Add image ? --
-- --
- -- -
-
-
-@@ -78,7 +80,7 @@ email : ranihaileydesai@gmail.com -
- - -- -+
- - -


-diff --git a/ui/viewpost.html b/ui/viewpost.html -index dacbae5..40e2455 100644 ---- a/ui/viewpost.html -+++ b/ui/viewpost.html -@@ -43,6 +43,8 @@ email : ranihaileydesai@gmail.com -

{{post.description_post}}

- -
-+ -+ {% if post.link_post %} -
-
-
-@@ -53,6 +55,8 @@ email : ranihaileydesai@gmail.com -

{{post.link_post}}

-
-
-+ {% endif %} -+ -
- -
-diff --git a/webhub/models.py b/webhub/models.py -index 6c46594..a22d034 100644 ---- a/webhub/models.py -+++ b/webhub/models.py -@@ -72,7 +72,7 @@ class Post(models.Model): - updated = models.DateTimeField(auto_now=True) - - #path to default post image -- image_post = models.CharField(max_length=300, default="http://i.imgur.com/dnjclWV.png") -+ image_post = models.CharField(max_length=300, default="http://allfacebook.com/files/2012/03/bluepin.png") - #image of the post - imageobj_post = models.ImageField(upload_to=update_filename1) - -diff --git a/webhub/models.pyc b/webhub/models.pyc -index ac06547..4af9dd2 100644 -Binary files a/webhub/models.pyc and b/webhub/models.pyc differ -diff --git a/webhub/views.py b/webhub/views.py -index 4c6cb57..a965b5f 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -353,8 +353,9 @@ def post_new(request): - title_post = request.REQUEST['title'] - description_post = request.REQUEST['description'] - link_post = request.REQUEST['link'] -- image_post = '/static/' + owner.user.username + "post.jpg" - imageobj_post = request.FILES['image_post'] -+ image_post = '/static/' + owner.user.username + "post.jpg" -+ - - entry = Post(owner=owner, - title_post=title_post, -@@ -404,7 +405,7 @@ def edit_post(request): - - #To remove post picture - if 'reset_image' in request.REQUEST.keys(): -- postobj.image_post = "http://vfcstatic.r.worldssl.net/assets/car_icon-e0df962a717a5db6ebc8b37e80b05713.png" -+ postobj.image_post = "http://allfacebook.com/files/2012/03/bluepin.png" - if str(postobj.imageobj_post) <> '': - path = '/vagrant/submit/media/propics/' + owner.user.username + "post.jpg" - if os.path.isfile(path): -@@ -422,10 +423,6 @@ def edit_post(request): - postobj.imageobj_post = request.FILES['image'] - postobj.image_post = '/static/' + owner.user.username + "post.jpg" - -- -- -- -- - if postobj.title_post <> title_post: - if postobj.description_post <> description_post: - if postobj.link_post <> link_post: -diff --git a/webhub/views.pyc b/webhub/views.pyc -index cb9e5ce..84e3031 100644 -Binary files a/webhub/views.pyc and b/webhub/views.pyc differ - -commit 23c946ac6c05aba2a8f8caee85d87f518ab5941c -Author: desaivaibhavi -Date: Tue Jun 24 02:09:02 2014 +0000 - - image field added in post - -diff --git a/ui/editpost.html b/ui/editpost.html -index d790a39..aa4e68c 100644 ---- a/ui/editpost.html -+++ b/ui/editpost.html -@@ -17,13 +17,13 @@ email : ranihaileydesai@gmail.com - -

Malaria : infoHub

- --
-+
-
-

Edit Post

-
- - --
-+ - -
-
-@@ -43,7 +43,6 @@ email : ranihaileydesai@gmail.com -
-
- -- -
-
- -@@ -60,6 +59,25 @@ email : ranihaileydesai@gmail.com -
-
- -+ -+
-+
-+
-+
-+

Change image

-+
-+
-+ -+
-+
-+ -+ -+
-+
-+ -+
-+
-+ -
- -
-@@ -74,13 +92,14 @@ email : ranihaileydesai@gmail.com -
-
-
-- -- -- - -+ -+
- - - -+ -+ -

- {% include "footer.html" %} - -diff --git a/ui/newpost.html b/ui/newpost.html -index 637eadf..8d62dc1 100644 ---- a/ui/newpost.html -+++ b/ui/newpost.html -@@ -20,7 +20,7 @@ email : ranihaileydesai@gmail.com -

New Post

-
- --
-+ - -
-
-@@ -57,6 +57,14 @@ email : ranihaileydesai@gmail.com - -
- -+ -+
-+ Add image ? -+
-+ -+
-+ -+ -
-
-
-diff --git a/ui/viewpost.html b/ui/viewpost.html -index b612529..dacbae5 100644 ---- a/ui/viewpost.html -+++ b/ui/viewpost.html -@@ -16,7 +16,7 @@ email : ranihaileydesai@gmail.com -





- -

Malaria : infoHub

--
-+
-
- -

View Post

-@@ -54,10 +54,17 @@ email : ranihaileydesai@gmail.com -
-

-
-+ -+
-+ -+
-+
-      - -
- -+ -+ -
-
-
-diff --git a/webhub/models.py b/webhub/models.py -index b0ffc12..6c46594 100644 ---- a/webhub/models.py -+++ b/webhub/models.py -@@ -19,6 +19,11 @@ def update_filename(instance, filename): - format = instance.user.username + ".jpg" - return os.path.join(path, format) - -+#To update the filename of the newly uploaded photo of the post -+def update_filename1(instance, filename): -+ path = '/vagrant/submit/media/propics/' -+ format = instance.owner.user.username + "post.jpg" -+ return os.path.join(path, format) - - #Django provides a table called user that stores basic user information like username, password and email id. - -@@ -65,6 +70,11 @@ class Post(models.Model): - created = models.DateTimeField(auto_now_add=True) - #field to note the timestamp when the post was last updated - updated = models.DateTimeField(auto_now=True) -+ -+ #path to default post image -+ image_post = models.CharField(max_length=300, default="http://i.imgur.com/dnjclWV.png") -+ #image of the post -+ imageobj_post = models.ImageField(upload_to=update_filename1) - - def __unicode__(self): - return self.owner.user.username -@@ -82,6 +92,8 @@ class RevPost(models.Model): - description_post_rev = models.CharField(max_length=2000) - #revised link to important documents - link_post_rev = models.CharField(max_length=2000) -+ -+ - #field to note the timestamp when the revised version was created - created = models.DateTimeField(auto_now_add=True) - #change in title -@@ -89,7 +101,8 @@ class RevPost(models.Model): - #change in description - description_change = models.BooleanField(default=False) - #change in link to important documents -- link_change = models.CharField(max_length=2000) -+ link_change = models.BooleanField(default=False) -+ - - - def __unicode__(self): -diff --git a/webhub/models.pyc b/webhub/models.pyc -index 32bd348..ac06547 100644 -Binary files a/webhub/models.pyc and b/webhub/models.pyc differ -diff --git a/webhub/views.py b/webhub/views.py -index f6f6bc9..4c6cb57 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -353,11 +353,15 @@ def post_new(request): - title_post = request.REQUEST['title'] - description_post = request.REQUEST['description'] - link_post = request.REQUEST['link'] -+ image_post = '/static/' + owner.user.username + "post.jpg" -+ imageobj_post = request.FILES['image_post'] - - entry = Post(owner=owner, - title_post=title_post, - description_post=description_post, - link_post=link_post, -+ imageobj_post=imageobj_post, -+ image_post=image_post, - ) - entry.save() - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, -@@ -397,6 +401,31 @@ def edit_post(request): - description_post = request.REQUEST['description'] - link_post = request.REQUEST['link'] - -+ -+ #To remove post picture -+ if 'reset_image' in request.REQUEST.keys(): -+ postobj.image_post = "http://vfcstatic.r.worldssl.net/assets/car_icon-e0df962a717a5db6ebc8b37e80b05713.png" -+ if str(postobj.imageobj_post) <> '': -+ path = '/vagrant/submit/media/propics/' + owner.user.username + "post.jpg" -+ if os.path.isfile(path): -+ os.remove(path) -+ postobj.save() -+ return edit_post(request) -+ -+ -+ if 'image' in request.FILES.keys(): -+ #delete old file -+ if str(postobj.imageobj_post) <> '': -+ path = '/vagrant/submit/media/propics/' + owner.user.username + "post.jpg" -+ if os.path.isfile(path): -+ os.remove(path) -+ postobj.imageobj_post = request.FILES['image'] -+ postobj.image_post = '/static/' + owner.user.username + "post.jpg" -+ -+ -+ -+ -+ - if postobj.title_post <> title_post: - if postobj.description_post <> description_post: - if postobj.link_post <> link_post: -diff --git a/webhub/views.pyc b/webhub/views.pyc -index b69e3fb..cb9e5ce 100644 -Binary files a/webhub/views.pyc and b/webhub/views.pyc differ - -commit f934eff8c2824d35450a236504edd966b75b1c14 -Author: desaivaibhavi -Date: Mon Jun 23 23:46:42 2014 +0000 - - small touching up in footer - -diff --git a/ui/aboutPC.html b/ui/aboutPC.html -new file mode 100644 -index 0000000..91cb4d5 ---- /dev/null -+++ b/ui/aboutPC.html -@@ -0,0 +1,23 @@ -+ -+ -+ -+ -+ -+ About PC -+ -+ -+ {% include "header.html" %} -+





-+

Here the information about PC would be shown

-+ -+

















-+ {% include "footer.html" %} -+ -+ -+ -+ -diff --git a/ui/details.html b/ui/details.html -new file mode 100644 -index 0000000..082a0d6 ---- /dev/null -+++ b/ui/details.html -@@ -0,0 +1,23 @@ -+ -+ -+ -+ -+ -+ About PC -+ -+ -+ {% include "header.html" %} -+





-+

Here the details would be shown

-+ -+

















-+ {% include "footer.html" %} -+ -+ -+ -+ -diff --git a/ui/footer.html b/ui/footer.html -index c6738ed..b15b8db 100644 ---- a/ui/footer.html -+++ b/ui/footer.html -@@ -43,11 +43,11 @@ div{ -
- - --
-- About Peace Corps   |   -- Policies   |   -- Important Details   |   -- Help   -+
-+ About Peace Corps  |   -+ Policies  |   -+ Important Details  |   -+ Help   -

-
-
-diff --git a/ui/helpPC.html b/ui/helpPC.html -new file mode 100644 -index 0000000..4161404 ---- /dev/null -+++ b/ui/helpPC.html -@@ -0,0 +1,23 @@ -+ -+ -+ -+ -+ -+ Help PC -+ -+ -+ {% include "header.html" %} -+





-+

Here the help information about PC would be shown

-+ -+

















-+ {% include "footer.html" %} -+ -+ -+ -+ -diff --git a/ui/policies.html b/ui/policies.html -new file mode 100644 -index 0000000..203cb8b ---- /dev/null -+++ b/ui/policies.html -@@ -0,0 +1,23 @@ -+ -+ -+ -+ -+ -+ About PC -+ -+ -+ {% include "header.html" %} -+





-+

Here the information about policies would be shown

-+ -+

















-+ {% include "footer.html" %} -+ -+ -+ -+ -diff --git a/ui/viewpost.html b/ui/viewpost.html -index 01aeca5..b612529 100644 ---- a/ui/viewpost.html -+++ b/ui/viewpost.html -@@ -61,7 +61,7 @@ email : ranihaileydesai@gmail.com -
-
-
--

-+

-

Revision History of this Post


- -
-@@ -72,7 +72,7 @@ email : ranihaileydesai@gmail.com - - - {% for rev in revpostobj %} --
  • The post was updated by {{rev.owner_rev.user.first_name}} on {{rev.created}}
  • -+
  • The post was updated by {{rev.owner_rev.user.first_name}} on {{rev.created}}
  • - -
    - {% if rev.title_change %} -@@ -81,6 +81,10 @@ email : ranihaileydesai@gmail.com - {% if rev.description_change %} - The description has been changed from "{{rev.description_post_rev}}" to "{{post.description_post}}" - {% endif %} -+ {% if rev.link_change %} -+ The link has been changed from "{{rev.link_post_rev}}" to "{{post.link_post}}" -+ {% endif %} -+ -
    - - {% endfor %} -diff --git a/webhub/urls.py b/webhub/urls.py -index 633f3c2..d9c9dd1 100644 ---- a/webhub/urls.py -+++ b/webhub/urls.py -@@ -45,9 +45,13 @@ urlpatterns = patterns('', - url(r'^post/(?P[0-9]+)/$', views.post_detail, name='post_detail'), - url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), - url(r'^api/', include(router.urls)), -- -+ url(r'^aboutPC/$', views.aboutPC, name='aboutPC'), -+ url(r'^policies/$', views.policies, name='policies'), -+ url(r'^details/$', views.details, name='details'), -+ url(r'^helpPC/$', views.helpPC, name='helpPC'), - ) - - - - -+ -diff --git a/webhub/urls.pyc b/webhub/urls.pyc -index 973ce4e..73b49f9 100644 -Binary files a/webhub/urls.pyc and b/webhub/urls.pyc differ -diff --git a/webhub/views.py b/webhub/views.py -index f09d960..f6f6bc9 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -726,3 +726,20 @@ def change_pass_page(request): - def peacetrack(request): - return HttpResponse(jinja_environ.get_template('peacetrack.html').render({"pcuser":None})) - -+#called when user wishes to go to the Peacetrack from dashboard -+def aboutPC(request): -+ return HttpResponse(jinja_environ.get_template('aboutPC.html').render({"pcuser":None})) -+ -+#called when user wishes to go to the Peacetrack from dashboard -+def policies(request): -+ return HttpResponse(jinja_environ.get_template('policies.html').render({"pcuser":None})) -+ -+#called when user wishes to go to the Peacetrack from dashboard -+def details(request): -+ return HttpResponse(jinja_environ.get_template('details.html').render({"pcuser":None})) -+ -+#called when user wishes to go to the Peacetrack from dashboard -+def helpPC(request): -+ return HttpResponse(jinja_environ.get_template('helpPC.html').render({"pcuser":None})) -+ -+ -diff --git a/webhub/views.pyc b/webhub/views.pyc -index 71b0bce..b69e3fb 100644 -Binary files a/webhub/views.pyc and b/webhub/views.pyc differ - -commit 8cf1b621e0fc3d5a1ce1498c661b1387e07c6860 -Author: desaivaibhavi -Date: Mon Jun 23 21:15:59 2014 +0000 - - link added along with the post - -diff --git a/infohub/settings.py b/infohub/settings.py -index 93cefd3..c3ad798 100644 ---- a/infohub/settings.py -+++ b/infohub/settings.py -@@ -30,7 +30,6 @@ INSTALLED_APPS = ( - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', -- 'django.contrib.sites', - 'django.contrib.staticfiles', - 'webhub', - 'rest_framework', -diff --git a/infohub/settings.pyc b/infohub/settings.pyc -index 7dd8b85..7ab205b 100644 -Binary files a/infohub/settings.pyc and b/infohub/settings.pyc differ -diff --git a/ui/editpost.html b/ui/editpost.html -index 643f706..d790a39 100644 ---- a/ui/editpost.html -+++ b/ui/editpost.html -@@ -17,7 +17,7 @@ email : ranihaileydesai@gmail.com - -

    Malaria : infoHub

    - --
    -+
    -
    -

    Edit Post

    -
    -@@ -46,6 +46,20 @@ email : ranihaileydesai@gmail.com - -
    -
    -+ -+
    -+
    -+
    -+
    -+
    -+

    Link

    -+
    -+
    -+ -+ -+
    -+
    -+ -
    - -
    -diff --git a/ui/newpost.html b/ui/newpost.html -index 1a09c6a..637eadf 100644 ---- a/ui/newpost.html -+++ b/ui/newpost.html -@@ -15,7 +15,7 @@ email : ranihaileydesai@gmail.com -





    -

    Malaria : infoHub

    - --
    -+
    -
    -

    New Post

    -
    -@@ -43,13 +43,25 @@ email : ranihaileydesai@gmail.com - -
    -
    -+
    -+
    -+
    -+
    -+
    -+

    Link

    -+
    -+
    -+ -+
    -+
    -+ -
    - -
    -
    -
    -
    -- -+ -
    -
    -diff --git a/ui/viewpost.html b/ui/viewpost.html -index 0ed988a..01aeca5 100644 ---- a/ui/viewpost.html -+++ b/ui/viewpost.html -@@ -16,7 +16,7 @@ email : ranihaileydesai@gmail.com -





    - -

    Malaria : infoHub

    --
    -+
    -
    - -

    View Post

    -@@ -43,6 +43,16 @@ email : ranihaileydesai@gmail.com -

    {{post.description_post}}

    -
    -

    -+
    -+
    -+
    -+
    -+

    Link :

    -+
    -+ -+

    -
    -      - -diff --git a/webhub/models.py b/webhub/models.py -index fd96783..b0ffc12 100644 ---- a/webhub/models.py -+++ b/webhub/models.py -@@ -35,6 +35,7 @@ class Pcuser(models.Model): - #for reset_password - reset_pass = models.CharField(default="",max_length=320) - -+ - #path to default user image - image = models.CharField(max_length=300, default="http://i.imgur.com/dnjclWV.png") - #image -@@ -58,6 +59,8 @@ class Post(models.Model): - title_post = models.CharField(max_length=300) - #description - description_post = models.CharField(max_length=2000) -+ #link to important documents -+ link_post = models.CharField(max_length=2000) - #field to note the timestamp when the post was created - created = models.DateTimeField(auto_now_add=True) - #field to note the timestamp when the post was last updated -@@ -77,12 +80,16 @@ class RevPost(models.Model): - title_post_rev = models.CharField(max_length=300) - #revised description - description_post_rev = models.CharField(max_length=2000) -+ #revised link to important documents -+ link_post_rev = models.CharField(max_length=2000) - #field to note the timestamp when the revised version was created - created = models.DateTimeField(auto_now_add=True) - #change in title - title_change = models.BooleanField(default=False) - #change in description - description_change = models.BooleanField(default=False) -+ #change in link to important documents -+ link_change = models.CharField(max_length=2000) - - - def __unicode__(self): -diff --git a/webhub/models.pyc b/webhub/models.pyc -index e18c7be..32bd348 100644 -Binary files a/webhub/models.pyc and b/webhub/models.pyc differ -diff --git a/webhub/views.py b/webhub/views.py -index 4e15556..f09d960 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -352,10 +352,12 @@ def post_new(request): - owner = request.user.pcuser - title_post = request.REQUEST['title'] - description_post = request.REQUEST['description'] -+ link_post = request.REQUEST['link'] - - entry = Post(owner=owner, - title_post=title_post, - description_post=description_post, -+ link_post=link_post, - ) - entry.save() - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, -@@ -393,52 +395,113 @@ def edit_post(request): - - title_post = request.REQUEST['title'] - description_post = request.REQUEST['description'] -+ link_post = request.REQUEST['link'] - - if postobj.title_post <> title_post: - if postobj.description_post <> description_post: -- entry = RevPost(owner_rev=owner, -- owner_rev_post=postobj, -- title_post_rev=postobj.title_post, -- description_post_rev=postobj.description_post, -- title_change=True, -- description_change=True, -- ) -- entry.save() -+ if postobj.link_post <> link_post: -+ entry = RevPost(owner_rev=owner, -+ owner_rev_post=postobj, -+ title_post_rev=postobj.title_post, -+ description_post_rev=postobj.description_post, -+ link_post_rev=postobj.link_post, -+ title_change=True, -+ description_change=True, -+ link_change=True, -+ ) -+ entry.save() -+ else: -+ entry = RevPost(owner_rev=owner, -+ owner_rev_post=postobj, -+ title_post_rev=postobj.title_post, -+ description_post_rev=postobj.description_post, -+ link_post_rev=postobj.link_post, -+ title_change=True, -+ description_change=True, -+ link_change=False, -+ ) -+ entry.save() - else: -- entry = RevPost(owner_rev=owner, -- owner_rev_post=postobj, -- title_post_rev=postobj.title_post, -- description_post_rev=postobj.description_post, -- title_change=True, -- description_change=False, -- ) -- entry.save() -+ if postobj.link_post <> link_post: -+ entry = RevPost(owner_rev=owner, -+ owner_rev_post=postobj, -+ title_post_rev=postobj.title_post, -+ description_post_rev=postobj.description_post, -+ link_post_rev=postobj.link_post, -+ title_change=True, -+ description_change=False, -+ link_change=True, -+ ) -+ entry.save() -+ else: -+ entry = RevPost(owner_rev=owner, -+ owner_rev_post=postobj, -+ title_post_rev=postobj.title_post, -+ description_post_rev=postobj.description_post, -+ link_post_rev=postobj.link_post, -+ title_change=True, -+ description_change=False, -+ link_change=False, -+ ) -+ entry.save() -+ -+ - else: - if postobj.description_post <> description_post: -- entry = RevPost(owner_rev=owner, -- owner_rev_post=postobj, -- title_post_rev=postobj.title_post, -- description_post_rev=postobj.description_post, -- title_change=False, -- description_change=True, -- ) -- entry.save() -+ if postobj.link_post <> link_post: -+ entry = RevPost(owner_rev=owner, -+ owner_rev_post=postobj, -+ title_post_rev=postobj.title_post, -+ description_post_rev=postobj.description_post, -+ link_post_rev=postobj.link_post, -+ title_change=False, -+ description_change=True, -+ link_change=True, -+ ) -+ entry.save() -+ else: -+ entry = RevPost(owner_rev=owner, -+ owner_rev_post=postobj, -+ title_post_rev=postobj.title_post, -+ description_post_rev=postobj.description_post, -+ link_post_rev=postobj.link_post, -+ title_change=False, -+ description_change=True, -+ link_change=False, -+ ) -+ entry.save() -+ -+ - else: -- entry = RevPost(owner_rev=owner, -- owner_rev_post=postobj, -- title_post_rev=postobj.title_post, -- description_post_rev=postobj.description_post, -- title_change=False, -- description_change=False, -- ) -- entry.save() -- -- -+ if postobj.link_post <> link_post: -+ entry = RevPost(owner_rev=owner, -+ owner_rev_post=postobj, -+ title_post_rev=postobj.title_post, -+ description_post_rev=postobj.description_post, -+ link_post_rev=postobj.link_post, -+ title_change=False, -+ description_change=False, -+ link_change=True, -+ ) -+ entry.save() -+ else: -+ entry = RevPost(owner_rev=owner, -+ owner_rev_post=postobj, -+ title_post_rev=postobj.title_post, -+ description_post_rev=postobj.description_post, -+ link_post_rev=postobj.link_post, -+ title_change=False, -+ description_change=False, -+ link_change=False, -+ ) -+ entry.save() -+ - - - - postobj.title_post = title_post - postobj.description_post = description_post -+ postobj.link_post = link_post - - postobj.save() - -diff --git a/webhub/views.pyc b/webhub/views.pyc -index 0fe6bef..71b0bce 100644 -Binary files a/webhub/views.pyc and b/webhub/views.pyc differ - -commit e9a52568c739109b89e8d57f9cc3d2b8dff7b11d -Author: desaivaibhavi -Date: Mon Jun 23 12:35:54 2014 +0000 - - user profile icon working in static manner, small suggestions incorporated - -diff --git a/infohub/settings.py b/infohub/settings.py -index ce5237e..93cefd3 100644 ---- a/infohub/settings.py -+++ b/infohub/settings.py -@@ -19,7 +19,7 @@ DEBUG = True - - TEMPLATE_DEBUG = True - --ALLOWED_HOSTS = [] -+ALLOWED_HOSTS = ['localhost','192.168.33.10','192.168.33.10:8000'] - - - # Application definition -@@ -30,7 +30,8 @@ INSTALLED_APPS = ( - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', -- 'django.contrib.staticfiles', -+ 'django.contrib.sites', -+ 'django.contrib.staticfiles', - 'webhub', - 'rest_framework', - ) -@@ -79,8 +80,21 @@ USE_TZ = True - - # Static files (CSS, JavaScript, Images) - # https://docs.djangoproject.com/en/1.6/howto/static-files/ -- -+MEDIA_ROOT='/vagrant/submit/media/propics/' - STATIC_URL = '/static/' -+STATIC_ROOT = '' -+ -+# Additional locations of static files -+STATICFILES_DIRS = ( -+ '/vagrant/submit/media/propics/', -+ '/vagrant/submit/app-web-server/ui/bootstrap/fonts', -+ 'lol', -+) -+STATICFILES_FINDERS = ( -+ 'django.contrib.staticfiles.finders.FileSystemFinder', -+ 'django.contrib.staticfiles.finders.AppDirectoriesFinder', -+) -+ - - REST_FRAMEWORK = { - 'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAdminUser',), -diff --git a/infohub/settings.pyc b/infohub/settings.pyc -index 3a8eb23..7dd8b85 100644 -Binary files a/infohub/settings.pyc and b/infohub/settings.pyc differ -diff --git a/paths.py b/paths.py -new file mode 100644 -index 0000000..dd053eb ---- /dev/null -+++ b/paths.py -@@ -0,0 +1 @@ -+cpspath='/home/rani/gsoc/DevEnvironments/pc-web/submit/' -diff --git a/paths.pyc b/paths.pyc -new file mode 100644 -index 0000000..b57516b -Binary files /dev/null and b/paths.pyc differ -diff --git a/ui/edit_profile.html b/ui/edit_profile.html -index 193c4e2..0fd7171 100644 ---- a/ui/edit_profile.html -+++ b/ui/edit_profile.html -@@ -17,7 +17,7 @@ email : ranihaileydesai@gmail.com -





    - - --
    -+
    -
    -

    Edit Profile

    -
    -@@ -27,7 +27,7 @@ email : ranihaileydesai@gmail.com -
    -
    -
    -- -+ - - - -@@ -56,11 +56,16 @@ email : ranihaileydesai@gmail.com - -
    - -+
    -+ Change Profile Photo: -+
    -+ -+
    - -
    -
    -
    -- -+ -

    User {{pcuser.user}}

    -
    -
    -@@ -79,5 +84,8 @@ email : ranihaileydesai@gmail.com - -

    - {% include "footer.html" %} -+ -+ -+ - - -\ No newline at end of file -diff --git a/ui/profile.html b/ui/profile.html -index 07cdbcd..c31bde5 100644 ---- a/ui/profile.html -+++ b/ui/profile.html -@@ -34,7 +34,7 @@ email : ranihaileydesai@gmail.com -
    -
    -
    -- -+ -

    User {{profiler.user}}

    -
    -
    -@@ -43,7 +43,7 @@ email : ranihaileydesai@gmail.com -
    -

    -
    -- {% if profiler.user.username == pcuser .user.username %} -+ {% if profiler.user.username == pcuser.user.username %} - - {% endif %} - -diff --git a/ui/signup.html b/ui/signup.html -index 3f6eea4..9155bc4 100644 ---- a/ui/signup.html -+++ b/ui/signup.html -@@ -29,10 +29,10 @@ email : ranihaileydesai@gmail.com - -
    - - -
    - -diff --git a/webhub/models.py b/webhub/models.py -index d78b033..fd96783 100644 ---- a/webhub/models.py -+++ b/webhub/models.py -@@ -9,9 +9,20 @@ from django.utils import timezone - from django.contrib.auth.models import User - import os - from uuid import uuid4 -+from paths import cpspath -+ -+ -+ -+#To update the filename of the newly uploaded photo -+def update_filename(instance, filename): -+ path = '/vagrant/submit/media/propics/' -+ format = instance.user.username + ".jpg" -+ return os.path.join(path, format) -+ - - #Django provides a table called user that stores basic user information like username, password and email id. - -+ - class Pcuser(models.Model): - #username - user = models.OneToOneField(User) -@@ -24,6 +35,11 @@ class Pcuser(models.Model): - #for reset_password - reset_pass = models.CharField(default="",max_length=320) - -+ #path to default user image -+ image = models.CharField(max_length=300, default="http://i.imgur.com/dnjclWV.png") -+ #image -+ imageobj = models.ImageField(upload_to=update_filename) -+ - #verification status - #1 - unverified - #any other number = verification code -@@ -31,8 +47,8 @@ class Pcuser(models.Model): - - def __unicode__(self): - return self.user.username -- -- -+ -+ - #Post table stores details about posts - - class Post(models.Model): -diff --git a/webhub/models.pyc b/webhub/models.pyc -index c58fd53..e18c7be 100644 -Binary files a/webhub/models.pyc and b/webhub/models.pyc differ -diff --git a/webhub/views.py b/webhub/views.py -index 193ea51..4e15556 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -26,6 +26,7 @@ from rest_framework import permissions - from rest_framework import status - from rest_framework.decorators import api_view - from rest_framework.response import Response -+from paths import cpspath - - import smtplib - -@@ -358,8 +359,7 @@ def post_new(request): - ) - entry.save() - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, -- "text":'Post successful.',"text1":'Click here to go to home.', -- "link": '/'})) -+ "text":'Post created successfully.',"text1":'Click here to view post.', "link": '/view_post/?key=' + str(entry.id)})) - - #Calls the edit post page. Also, sends the autofill form data. - def edit_post_page(request): -@@ -496,6 +496,29 @@ def edit_profile(request): - return HttpResponse(jinja_environ.get_template('index.html').render({"pcuser":None})) - - -+ #To remove profile picture -+ if 'reset_image' in request.REQUEST.keys(): -+ request.user.pcuser.image = "http://vfcstatic.r.worldssl.net/assets/car_icon-e0df962a717a5db6ebc8b37e80b05713.png" -+ if str(request.user.pcuser.imageobj) <> '': -+ path = '/vagrant/submit/media/propics/' + request.user.username + request.user.pcuser.imageobj.url[request.user.pcuser.imageobj.url.rfind('.'):] -+ if os.path.isfile(path): -+ os.remove(path) -+ request.user.pcuser.save() -+ return edit_profile_page(request) -+ -+ -+ if 'image' in request.FILES.keys(): -+ #delete old file -+ if str(request.user.pcuser.imageobj) <> '': -+ path = '/vagrant/submit/media/propics/' + request.user.username + ".jpg" -+ if os.path.isfile(path): -+ os.remove(path) -+ request.user.pcuser.imageobj = request.FILES['image'] -+ request.user.pcuser.image = '/static/' + request.user.username + ".jpg" -+ -+ -+ -+ - - - request.user.pcuser.gender = request.REQUEST['gender'] -diff --git a/webhub/views.pyc b/webhub/views.pyc -index a9bfc6e..0fe6bef 100644 -Binary files a/webhub/views.pyc and b/webhub/views.pyc differ - -commit 68c70b64f36942f773fbef4cb96396b08f9df011 -Author: desaivaibhavi -Date: Mon Jun 16 15:56:53 2014 +0000 - - user can edit only his own profile - -diff --git a/ui/profile.html b/ui/profile.html -index 59b7397..07cdbcd 100644 ---- a/ui/profile.html -+++ b/ui/profile.html -@@ -9,7 +9,7 @@ email : ranihaileydesai@gmail.com - - - -- User Profile | {{profiler.first_name}} -+ User Profile | {{profiler.user.first_name}} - - - {% include "header.html" %} -@@ -43,7 +43,9 @@ email : ranihaileydesai@gmail.com -
    -

    -
    -+ {% if profiler.user.username == pcuser .user.username %} - -+ {% endif %} - -
    - -diff --git a/ui/viewpost.html b/ui/viewpost.html -index 2fda4ff..0ed988a 100644 ---- a/ui/viewpost.html -+++ b/ui/viewpost.html -@@ -64,14 +64,14 @@ email : ranihaileydesai@gmail.com - {% for rev in revpostobj %} -
  • The post was updated by {{rev.owner_rev.user.first_name}} on {{rev.created}}
  • - --
    -+
    - {% if rev.title_change %} - The title has been changed from "{{rev.title_post_rev}}" to "{{post.title_post}}" - {% endif %} - {% if rev.description_change %} - The description has been changed from "{{rev.description_post_rev}}" to "{{post.description_post}}" - {% endif %} --
    -+
    - - {% endfor %} -
    - -commit 6aac759435604a98ededabd77893e2f04f82fd3e -Author: desaivaibhavi -Date: Mon Jun 16 15:46:54 2014 +0000 - - revision history module completed - -diff --git a/ui/viewpost.html b/ui/viewpost.html -index b888635..2fda4ff 100644 ---- a/ui/viewpost.html -+++ b/ui/viewpost.html -@@ -62,11 +62,17 @@ email : ranihaileydesai@gmail.com - - - {% for rev in revpostobj %} --
    The post was updated by {{rev.owner_rev.user.first_name}} on {{rev.created}}
    --
    -- -- --
    -+
  • The post was updated by {{rev.owner_rev.user.first_name}} on {{rev.created}}
  • -+ -+
    -+ {% if rev.title_change %} -+ The title has been changed from "{{rev.title_post_rev}}" to "{{post.title_post}}" -+ {% endif %} -+ {% if rev.description_change %} -+ The description has been changed from "{{rev.description_post_rev}}" to "{{post.description_post}}" -+ {% endif %} -+
    -+ - {% endfor %} -
    -
    -diff --git a/webhub/models.py b/webhub/models.py -index 88a752d..d78b033 100644 ---- a/webhub/models.py -+++ b/webhub/models.py -@@ -63,6 +63,10 @@ class RevPost(models.Model): - description_post_rev = models.CharField(max_length=2000) - #field to note the timestamp when the revised version was created - created = models.DateTimeField(auto_now_add=True) -+ #change in title -+ title_change = models.BooleanField(default=False) -+ #change in description -+ description_change = models.BooleanField(default=False) - - - def __unicode__(self): -diff --git a/webhub/models.pyc b/webhub/models.pyc -index feb1297..c58fd53 100644 -Binary files a/webhub/models.pyc and b/webhub/models.pyc differ -diff --git a/webhub/views.py b/webhub/views.py -index 9980509..193ea51 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -391,15 +391,50 @@ def edit_post(request): - except Exception as e: - return HttpResponse(e) - -- entry = RevPost(owner_rev=owner, -- owner_rev_post=postobj, -+ title_post = request.REQUEST['title'] -+ description_post = request.REQUEST['description'] -+ -+ if postobj.title_post <> title_post: -+ if postobj.description_post <> description_post: -+ entry = RevPost(owner_rev=owner, -+ owner_rev_post=postobj, - title_post_rev=postobj.title_post, - description_post_rev=postobj.description_post, -+ title_change=True, -+ description_change=True, - ) -- entry.save() -+ entry.save() -+ else: -+ entry = RevPost(owner_rev=owner, -+ owner_rev_post=postobj, -+ title_post_rev=postobj.title_post, -+ description_post_rev=postobj.description_post, -+ title_change=True, -+ description_change=False, -+ ) -+ entry.save() -+ else: -+ if postobj.description_post <> description_post: -+ entry = RevPost(owner_rev=owner, -+ owner_rev_post=postobj, -+ title_post_rev=postobj.title_post, -+ description_post_rev=postobj.description_post, -+ title_change=False, -+ description_change=True, -+ ) -+ entry.save() -+ else: -+ entry = RevPost(owner_rev=owner, -+ owner_rev_post=postobj, -+ title_post_rev=postobj.title_post, -+ description_post_rev=postobj.description_post, -+ title_change=False, -+ description_change=False, -+ ) -+ entry.save() - -- title_post = request.REQUEST['title'] -- description_post = request.REQUEST['description'] -+ -+ - - - postobj.title_post = title_post -diff --git a/webhub/views.pyc b/webhub/views.pyc -index 70fb5f2..a9bfc6e 100644 -Binary files a/webhub/views.pyc and b/webhub/views.pyc differ - -commit 7ab3f85e23af078b68ec621a25923589ef0a8c8c -Author: desaivaibhavi -Date: Mon Jun 16 14:00:37 2014 +0000 - - post and pcuser json format api done with authentication - -diff --git a/webhub/serializers.py b/webhub/serializers.py -index 4856677..4dddc6a 100644 ---- a/webhub/serializers.py -+++ b/webhub/serializers.py -@@ -12,4 +12,9 @@ class UserSerializer(serializers.HyperlinkedModelSerializer): - class PcuserSerializer(serializers.ModelSerializer): - class Meta: - model = Pcuser -- fields = ('user', 'location', 'phone', 'gender','id') -\ No newline at end of file -+ fields = ('user', 'location', 'phone', 'gender','id') -+ -+class PostSerializer(serializers.ModelSerializer): -+ class Meta: -+ model = Post -+ fields = ('owner', 'title_post', 'description_post', 'created','updated','id') -\ No newline at end of file -diff --git a/webhub/serializers.pyc b/webhub/serializers.pyc -index 91146b2..c8f09ba 100644 -Binary files a/webhub/serializers.pyc and b/webhub/serializers.pyc differ -diff --git a/webhub/urls.py b/webhub/urls.py -index f31c044..633f3c2 100644 ---- a/webhub/urls.py -+++ b/webhub/urls.py -@@ -6,6 +6,8 @@ - from django.conf.urls import patterns, url, include - from rest_framework import routers - from webhub import views -+ -+ - router = routers.DefaultRouter() - router.register(r'users', views.UserViewSet) - -@@ -38,13 +40,12 @@ urlpatterns = patterns('', - url(r'^change_pass/$', views.change_pass, name='change_pass'), - url(r'^change_pass_page/$', views.change_pass_page, name='change_pass_page'), - url(r'^pcuser/$', views.pcuser_list, name='pcuser_list'), -+ url(r'^post/$', views.post_list, name='post_list'), - url(r'^pcuser/(?P[0-9]+)/$', views.pcuser_detail, name='pcuser_detail'), -+ url(r'^post/(?P[0-9]+)/$', views.post_detail, name='post_detail'), - url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), - url(r'^api/', include(router.urls)), - -- -- -- - ) - - -diff --git a/webhub/urls.pyc b/webhub/urls.pyc -index 5357bae..973ce4e 100644 -Binary files a/webhub/urls.pyc and b/webhub/urls.pyc differ -diff --git a/webhub/views.py b/webhub/views.py -index 6961e84..9980509 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -22,6 +22,11 @@ from rest_framework import viewsets - from webhub.serializers import * - from rest_framework.renderers import JSONRenderer - from rest_framework.parsers import JSONParser -+from rest_framework import permissions -+from rest_framework import status -+from rest_framework.decorators import api_view -+from rest_framework.response import Response -+ - import smtplib - - #SMTP port for sending emails -@@ -40,67 +45,86 @@ class UserViewSet(viewsets.ModelViewSet): - queryset = User.objects.all() - serializer_class = UserSerializer - -- - --class JSONResponse(HttpResponse): -- """ -- An HttpResponse that renders its content into JSON. -- """ -- def __init__(self, data, **kwargs): -- content = JSONRenderer().render(data) -- kwargs['content_type'] = 'application/json' -- super(JSONResponse, self).__init__(content, **kwargs) -- -- -- --@csrf_exempt -+#List all pcusers, or create a new pcuser. -+@api_view(['GET', 'POST']) - def pcuser_list(request): -- """ -- List all code snippets, or create a new snippet. -- """ - if request.method == 'GET': - pcuser = Pcuser.objects.all() - serializer = PcuserSerializer(pcuser, many=True) -- return JSONResponse(serializer.data) -+ return Response(serializer.data) - - elif request.method == 'POST': -- data = JSONParser().parse(request) -- serializer = PcuserSerializer(data=data) -+ serializer = PcuserSerializer(data=request.DATA) - if serializer.is_valid(): - serializer.save() -- return JSONResponse(serializer.data, status=201) -- return JSONResponse(serializer.errors, status=400) -- -- --@csrf_exempt -+ return Response(serializer.data, status=status.HTTP_201_CREATED) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+#Retrieve, update or delete a pcuser instance. -+@api_view(['GET', 'PUT', 'DELETE']) - def pcuser_detail(request, pk): -- """ -- Retrieve, update or delete a code snippet. -- """ - try: - pcuser = Pcuser.objects.get(pk=pk) - except Pcuser.DoesNotExist: -- return HttpResponse(status=404) -+ return Response(status=status.HTTP_404_NOT_FOUND) - - if request.method == 'GET': - serializer = PcuserSerializer(pcuser) -- return JSONResponse(serializer.data) -+ return Response(serializer.data) - - elif request.method == 'PUT': -- data = JSONParser().parse(request) -- serializer = PcuserSerializer(pcuser, data=data) -+ serializer = PcuserSerializer(pcuser, data=request.DATA) - if serializer.is_valid(): - serializer.save() -- return JSONResponse(serializer.data) -- return JSONResponse(serializer.errors, status=400) -+ return Response(serializer.data) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - - elif request.method == 'DELETE': - pcuser.delete() -- return HttpResponse(status=204) -- -+ return Response(status=status.HTTP_204_NO_CONTENT) - - -+#List all posts, or create a new post. -+@api_view(['GET', 'POST']) -+def post_list(request): -+ if request.method == 'GET': -+ post = Post.objects.all() -+ serializer = PostSerializer(post, many=True) -+ return Response(serializer.data) - -+ elif request.method == 'POST': -+ serializer = PostSerializer(data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data, status=status.HTTP_201_CREATED) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+#Retrieve, update or delete a post instance. -+@api_view(['GET', 'PUT', 'DELETE']) -+def post_detail(request, pk): -+ try: -+ post = Post.objects.get(pk=pk) -+ except Pcuser.DoesNotExist: -+ return Response(status=status.HTTP_404_NOT_FOUND) -+ -+ if request.method == 'GET': -+ serializer = PostSerializer(post) -+ return Response(serializer.data) -+ -+ elif request.method == 'PUT': -+ serializer = PostSerializer(post, data=request.DATA) -+ if serializer.is_valid(): -+ serializer.save() -+ return Response(serializer.data) -+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -+ -+ elif request.method == 'DELETE': -+ post.delete() -+ return Response(status=status.HTTP_204_NO_CONTENT) -+ -+ -+ - #Calls index page - def index(request): - return HttpResponse(jinja_environ.get_template('index.html').render({"pcuser":None})) -diff --git a/webhub/views.pyc b/webhub/views.pyc -index 95bd05c..70fb5f2 100644 -Binary files a/webhub/views.pyc and b/webhub/views.pyc differ - -commit 4df79fcca33fc73a7020cd9b7ed323f0ec3bc625 -Author: desaivaibhavi -Date: Mon Jun 16 02:43:06 2014 +0000 - - minor changes required to the code - -diff --git a/ui/index.html b/ui/index.html -index e408276..5346f56 100644 ---- a/ui/index.html -+++ b/ui/index.html -@@ -26,7 +26,7 @@ email : ranihaileydesai@gmail.com -

    Username :

    - -

    Password :

    -- -+ -
    - Forgot Password ? -

    -diff --git a/ui/viewpost.html b/ui/viewpost.html -index 4d30cce..b888635 100644 ---- a/ui/viewpost.html -+++ b/ui/viewpost.html -@@ -59,7 +59,7 @@ email : ranihaileydesai@gmail.com -
    -
    -
    The post was created by {{post.owner}} on {{post.created}}
    --
    -+ - - {% for rev in revpostobj %} -
    The post was updated by {{rev.owner_rev.user.first_name}} on {{rev.created}}
    -diff --git a/webhub/models.py b/webhub/models.py -index 7bde5b8..88a752d 100644 ---- a/webhub/models.py -+++ b/webhub/models.py -@@ -66,4 +66,4 @@ class RevPost(models.Model): - - - def __unicode__(self): -- return self.owner.user.username -+ return self.owner_rev.user.username -diff --git a/webhub/models.pyc b/webhub/models.pyc -index 4c93dc0..feb1297 100644 -Binary files a/webhub/models.pyc and b/webhub/models.pyc differ -diff --git a/webhub/views.py b/webhub/views.py -index cd74bc4..6961e84 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -181,7 +181,7 @@ def signup_do(request): - send_verification_email(request) - - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -- "text":'

    Username already exists. Please enter some other username.

    Go Back or click OK to go to signup page.

    ',"link":'/signup_page/'})) -+ "text":'

    Verification email sent. check your inbox and verify the account.

    ',"text1":'

    Go Back or click OK to go to signup page.

    ',"link":'/signup_page/'})) - - - -@@ -227,7 +227,7 @@ def send_email(msg, email): - def verify(request): - if not request.user.is_authenticated(): - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -- "text":'Verification Successful. Go to homepage' , "link": '/'})) -+ "text":'Verification Successful.',"text1":'Go to homepage' , "link": '/'})) - # return HttpResponse(jinja_environ.get_template('index.html').render({"pcuser":Non, - # "code":request.REQUEST['code']})) - # index(request) -@@ -235,21 +235,21 @@ def verify(request): - request.user.pcuser - except: - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -- "text":'

    No Pcuser associated.

    Please go back or click OK to go to the homepage

    ',"link":'/'})) -+ "text":'

    No Pcuser associated.

    ',"text1":'

    Please click here to go to the homepage

    ',"link":'/'})) - - code = request.REQUEST['code'] - pcuser = request.user.pcuser - if pcuser.verified == '1': - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, -- "text":'

    Verification successful.

    Click OK to go to the homepage

    ',"link":'/'})) -+ "text":'

    Verification successful.

    ',"text1":'

    Click here to go to the homepage

    ',"link":'/'})) - elif code == pcuser.verified: - pcuser.verified = '1' - pcuser.save() - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, -- "text":'

    Verification successful.

    Click OK to go to the homepage

    ',"link":'/'})) -+ "text":'

    Verification successful.

    ',"text1":'

    Click here to go to the homepage

    ',"link":'/'})) - - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, -- "text":'

    Verification Failed.

    Please go back or click OK to go to the homepage

    ',"link":'/'})) -+ "text":'

    Verification Failed.

    ',"text1":'

    Please go back or click here to go to the homepage

    ',"link":'/'})) - - - -diff --git a/webhub/views.pyc b/webhub/views.pyc -index e13f0ee..95bd05c 100644 -Binary files a/webhub/views.pyc and b/webhub/views.pyc differ - -commit 30c93ae20443df7ec3e3531334fb4e533f97e79f -Author: desaivaibhavi -Date: Sat Jun 14 12:59:51 2014 +0000 - - user json api created - -diff --git a/webhub/serializers.py b/webhub/serializers.py -index 91f54a2..4856677 100644 ---- a/webhub/serializers.py -+++ b/webhub/serializers.py -@@ -9,3 +9,7 @@ class UserSerializer(serializers.HyperlinkedModelSerializer): - fields = ('url', 'username', 'email') - - -+class PcuserSerializer(serializers.ModelSerializer): -+ class Meta: -+ model = Pcuser -+ fields = ('user', 'location', 'phone', 'gender','id') -\ No newline at end of file -diff --git a/webhub/serializers.pyc b/webhub/serializers.pyc -index 3259576..91146b2 100644 -Binary files a/webhub/serializers.pyc and b/webhub/serializers.pyc differ -diff --git a/webhub/urls.py b/webhub/urls.py -index 00dbd68..f31c044 100644 ---- a/webhub/urls.py -+++ b/webhub/urls.py -@@ -37,9 +37,11 @@ urlpatterns = patterns('', - url(r'^reset_pass_page/$', views.reset_pass_page, name='reset_pass_page'), - url(r'^change_pass/$', views.change_pass, name='change_pass'), - url(r'^change_pass_page/$', views.change_pass_page, name='change_pass_page'), -+ url(r'^pcuser/$', views.pcuser_list, name='pcuser_list'), -+ url(r'^pcuser/(?P[0-9]+)/$', views.pcuser_detail, name='pcuser_detail'), - url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), - url(r'^api/', include(router.urls)), -- -+ - - - -diff --git a/webhub/urls.pyc b/webhub/urls.pyc -index 24dc1f9..5357bae 100644 -Binary files a/webhub/urls.pyc and b/webhub/urls.pyc differ -diff --git a/webhub/views.py b/webhub/views.py -index f5eaf55..cd74bc4 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -19,7 +19,9 @@ from jinja2.ext import loopcontrols - from webhub.checker import check - from webhub.models import * - from rest_framework import viewsets --from webhub.serializers import UserSerializer -+from webhub.serializers import * -+from rest_framework.renderers import JSONRenderer -+from rest_framework.parsers import JSONParser - import smtplib - - #SMTP port for sending emails -@@ -38,6 +40,63 @@ class UserViewSet(viewsets.ModelViewSet): - queryset = User.objects.all() - serializer_class = UserSerializer - -+ -+ -+class JSONResponse(HttpResponse): -+ """ -+ An HttpResponse that renders its content into JSON. -+ """ -+ def __init__(self, data, **kwargs): -+ content = JSONRenderer().render(data) -+ kwargs['content_type'] = 'application/json' -+ super(JSONResponse, self).__init__(content, **kwargs) -+ -+ -+ -+@csrf_exempt -+def pcuser_list(request): -+ """ -+ List all code snippets, or create a new snippet. -+ """ -+ if request.method == 'GET': -+ pcuser = Pcuser.objects.all() -+ serializer = PcuserSerializer(pcuser, many=True) -+ return JSONResponse(serializer.data) -+ -+ elif request.method == 'POST': -+ data = JSONParser().parse(request) -+ serializer = PcuserSerializer(data=data) -+ if serializer.is_valid(): -+ serializer.save() -+ return JSONResponse(serializer.data, status=201) -+ return JSONResponse(serializer.errors, status=400) -+ -+ -+@csrf_exempt -+def pcuser_detail(request, pk): -+ """ -+ Retrieve, update or delete a code snippet. -+ """ -+ try: -+ pcuser = Pcuser.objects.get(pk=pk) -+ except Pcuser.DoesNotExist: -+ return HttpResponse(status=404) -+ -+ if request.method == 'GET': -+ serializer = PcuserSerializer(pcuser) -+ return JSONResponse(serializer.data) -+ -+ elif request.method == 'PUT': -+ data = JSONParser().parse(request) -+ serializer = PcuserSerializer(pcuser, data=data) -+ if serializer.is_valid(): -+ serializer.save() -+ return JSONResponse(serializer.data) -+ return JSONResponse(serializer.errors, status=400) -+ -+ elif request.method == 'DELETE': -+ pcuser.delete() -+ return HttpResponse(status=204) - - - -diff --git a/webhub/views.pyc b/webhub/views.pyc -index 169c0f7..e13f0ee 100644 -Binary files a/webhub/views.pyc and b/webhub/views.pyc differ - -commit a8ec9535e065630cd9e6f2f046ffb1d4fea851a5 -Author: desaivaibhavi -Date: Fri Jun 13 12:03:02 2014 +0000 - - basic api created - -diff --git a/infohub/settings.py b/infohub/settings.py -index 6dba49a..ce5237e 100644 ---- a/infohub/settings.py -+++ b/infohub/settings.py -@@ -32,6 +32,7 @@ INSTALLED_APPS = ( - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'webhub', -+ 'rest_framework', - ) - - MIDDLEWARE_CLASSES = ( -@@ -80,3 +81,8 @@ USE_TZ = True - # https://docs.djangoproject.com/en/1.6/howto/static-files/ - - STATIC_URL = '/static/' -+ -+REST_FRAMEWORK = { -+ 'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAdminUser',), -+ 'PAGINATE_BY': 10 -+} -diff --git a/infohub/settings.pyc b/infohub/settings.pyc -index 8a1fa8f..3a8eb23 100644 -Binary files a/infohub/settings.pyc and b/infohub/settings.pyc differ -diff --git a/webhub/serializers.py b/webhub/serializers.py -new file mode 100644 -index 0000000..91f54a2 ---- /dev/null -+++ b/webhub/serializers.py -@@ -0,0 +1,11 @@ -+from django.contrib.auth.models import User -+from webhub.models import * -+ -+from rest_framework import serializers -+ -+class UserSerializer(serializers.HyperlinkedModelSerializer): -+ class Meta: -+ model = User -+ fields = ('url', 'username', 'email') -+ -+ -diff --git a/webhub/serializers.pyc b/webhub/serializers.pyc -new file mode 100644 -index 0000000..3259576 -Binary files /dev/null and b/webhub/serializers.pyc differ -diff --git a/webhub/urls.py b/webhub/urls.py -index b48a5c3..00dbd68 100644 ---- a/webhub/urls.py -+++ b/webhub/urls.py -@@ -3,9 +3,13 @@ - #Github username : desaivaibhavi - #email : ranihaileydesai@gmail.com - --from django.conf.urls import patterns, url -- -+from django.conf.urls import patterns, url, include -+from rest_framework import routers - from webhub import views -+router = routers.DefaultRouter() -+router.register(r'users', views.UserViewSet) -+ -+ - - urlpatterns = patterns('', - url(r'^index/$', views.index, name='index'), -@@ -33,6 +37,10 @@ urlpatterns = patterns('', - url(r'^reset_pass_page/$', views.reset_pass_page, name='reset_pass_page'), - url(r'^change_pass/$', views.change_pass, name='change_pass'), - url(r'^change_pass_page/$', views.change_pass_page, name='change_pass_page'), -+ url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), -+ url(r'^api/', include(router.urls)), -+ -+ - - - ) -diff --git a/webhub/urls.pyc b/webhub/urls.pyc -index 9a084e7..24dc1f9 100644 -Binary files a/webhub/urls.pyc and b/webhub/urls.pyc differ -diff --git a/webhub/views.py b/webhub/views.py -index dc634f9..f5eaf55 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -18,6 +18,8 @@ import uuid - from jinja2.ext import loopcontrols - from webhub.checker import check - from webhub.models import * -+from rest_framework import viewsets -+from webhub.serializers import UserSerializer - import smtplib - - #SMTP port for sending emails -@@ -28,6 +30,18 @@ website = "http://192.168.33.10:8000" - - jinja_environ = jinja2.Environment(loader=jinja2.FileSystemLoader(['ui']), extensions=[loopcontrols]) - -+ -+class UserViewSet(viewsets.ModelViewSet): -+ """ -+ API endpoint that allows users to be viewed or edited. -+ """ -+ queryset = User.objects.all() -+ serializer_class = UserSerializer -+ -+ -+ -+ -+ - #Calls index page - def index(request): - return HttpResponse(jinja_environ.get_template('index.html').render({"pcuser":None})) -diff --git a/webhub/views.pyc b/webhub/views.pyc -index 50e707a..169c0f7 100644 -Binary files a/webhub/views.pyc and b/webhub/views.pyc differ - -commit fd3caa08d69ef3c01cdf186e20b778be5417348b -Author: desaivaibhavi -Date: Wed Jun 11 22:31:55 2014 +0000 - - redirection pages - -diff --git a/ui/loginverify.html b/ui/loginverify.html -deleted file mode 100644 -index e69de29..0000000 -diff --git a/ui/viewpost.html b/ui/viewpost.html -index 5962859..4d30cce 100644 ---- a/ui/viewpost.html -+++ b/ui/viewpost.html -@@ -51,16 +51,22 @@ email : ranihaileydesai@gmail.com -
    -
    -
    --

    -+

    -

    Revision History of this Post


    - -
    -
    -
    -
    --

    The post was created by {{post.owner}} on {{post.created}}


    -+
    The post was created by {{post.owner}} on {{post.created}}
    -+
    -+ - {% for rev in revpostobj %} --

    The post was updated by {{rev.owner_rev.user.first_name}} on {{rev.created}}

    -+
    The post was updated by {{rev.owner_rev.user.first_name}} on {{rev.created}}
    -+
    -+ -+ -+
    - {% endfor %} -
    -
    -diff --git a/webhub/views.py b/webhub/views.py -index 7e6c0c1..dc634f9 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -397,18 +397,18 @@ def forgot_pass(request): - if request.user.is_authenticated(): - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'

    Please log out in order to request for a password reset.

    \ --

    Please go back or click OK to go to the homepage

    ',"link":'/'})) -+

    Please go back or click here to go to the homepage

    ',"link":'/'})) - if 'username' not in request.REQUEST.keys() or 'email' not in request.REQUEST.keys(): - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -- "text":'Invalid Request. Please go back or click OK to go to the homepage',"link":'/'})) -+ "text":'Invalid Request. Please go back or',"text1":'click here to go to the homepage',"link":'/'})) - user = User.objects.filter(username=request.REQUEST['username']) - if len(user) == 0: - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -- "text":'User Does not exist. Please go back or click OK to go to the homepage',"link":'/'})) -+ "text":'User Does not exist. Please go back or',"text1":'click here to go to the homepage',"link":'/'})) - user = user[0] - if user.email <> request.REQUEST['email']: - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -- "text":'Invalid email. Please go back or click OK to go to the homepage',"link":'/'})) -+ "text":'Invalid email. Please go back or',"text1":'click here to go to the homepage',"link":'/'})) - user.pcuser.reset_pass = uuid.uuid4().hex - user.pcuser.save() - -@@ -421,12 +421,11 @@ def forgot_pass(request): - x = send_email(msg, user.email) - if x[0] == 0: - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -- "text":'Could not process request, please try again later by going back or clicking OK to go to the homepage', "link":'/'})) -+ "text":'Could not process request, please try again later by going back or',"text1":'clicking here to go to the homepage', "link":'/'})) - else: - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'

    An email has been sent to your regestered email address.

    \ --

    Check your email and click on the link to reset your password.

    \ --

    Click OK to go to the homepage

    ',"link":'/'})) -+

    Check your email and click on the link to reset your password.

    ',"text1":'

    Click here to go to the homepage

    ',"link":'/'})) - - - -@@ -435,27 +434,24 @@ def forgot_pass(request): - def reset_pass_page(request): - if request.user.is_authenticated(): - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, -- "text":'

    Please log out before requesting reset in password.

    \ --

    Click OK to go to the homepage

    ',"link":'/'})) -+ "text":'

    Please log out before requesting reset in password.

    ',"text1":'

    Click here to go to the homepage

    ',"link":'/'})) - if "reset_pass" not in request.REQUEST.keys() or 'email' not in request.REQUEST.keys(): - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -- "text":'

    Invalid Request

    \ -- Click OK to go to the homepage

    ', "link":'/'})) -+ "text":'

    Invalid Request

    ',"text1":'Click here to go to the homepage

    ', "link":'/'})) - reset_pass = request.REQUEST['reset_pass'] - if reset_pass == "": - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -- "text":'

    Invalid Request

    \ --

    click OK to go to the homepage

    ', "link":'/'})) -+ "text":'

    Invalid Request

    ',"text1":'

    click here to go to the homepage

    ', "link":'/'})) - user = Pcuser.objects.filter(reset_pass=reset_pass) - if len(user)==0: - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -- "text":'Invalid Request. Please go back or click OK to go to the homepage',"link":'/'})) -+ "text":'Invalid Request.',"text1":'Please go back or click here to go to the homepage',"link":'/'})) - - user = user[0].user - - if user.email <> request.REQUEST['email']: - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -- "text":'Invalid Email. Please go back or click OK to go to the homepage',"link":'/'})) -+ "text":'Invalid Email.',"text1":'Please go back or click here to go to the homepage',"link":'/'})) - return HttpResponse(jinja_environ.get_template('reset_password.html').render({'pcuser':None, 'reset_pass':reset_pass})) - - -@@ -467,12 +463,11 @@ def change_pass(request): - reset_pass = request.REQUEST['reset_pass'] - if reset_pass == "": - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -- "text":'

    Invalid Request

    \ --

    click OK to go to the homepage

    ',"link":'/'})) -+ "text":'

    Invalid Request

    ', "text1":'

    click here to go to the homepage

    ',"link":'/'})) - user = Pcuser.objects.filter(reset_pass=reset_pass) - if len(user)==0 or 'pass' not in request.REQUEST.keys(): - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -- "text":'Invalid Request. Please go back or click OK to go to the homepage',"link":'/'})) -+ "text":'Invalid Request.',"text1":'Please go back or click here to go to the homepage',"link":'/'})) - user = user[0].user - user.set_password(request.REQUEST['pass']) - user.save() -@@ -480,22 +475,22 @@ def change_pass(request): - user.pcuser.save() - logout(request) - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -- "text":'Password Changed. Please click OK to go to the homepage and log in again.',"link":'/logout_do/'})) -+ "text":'Password Changed.',"text1":'Please click here to go to the homepage and log in again.',"link":'/logout_do/'})) - else: - retval = check(request) - if retval <> None: - return retval - if "pass" not in request.REQUEST.keys() or "oldpass" not in request.REQUEST.keys(): - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, -- "text":'Invalid Request. Please go back or click OK to go to the homepage',"link":'/'})) -+ "text":'Invalid Request.', "text1":'Please go back or click here to go to the homepage',"link":'/'})) - if not request.user.check_password(request.REQUEST['oldpass']): - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, -- "text":'Invalid Old Password. Click OK to go to the homepage',"link":'/'})) -+ "text":'Invalid Old Password.',"text1":'Click here to go to the homepage',"link":'/'})) - request.user.set_password(request.REQUEST['pass']) - request.user.save() - logout(request) - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -- "text":'Password Changed. Please click OK to go to the homepage and log in again.',"link":'/logout_do/'})) -+ "text":'Password Changed.',"text1":'Please click here to go to the homepage and log in again.',"link":'/logout_do/'})) - - - - -commit 7150442d5003a6b5c29e17159b5c15cb60a374ec -Author: desaivaibhavi -Date: Wed Jun 11 12:30:59 2014 +0000 - - forget password, change password, verify account complete - -diff --git a/ui/change_password.html b/ui/change_password.html -new file mode 100644 -index 0000000..914c56c ---- /dev/null -+++ b/ui/change_password.html -@@ -0,0 +1,67 @@ -+ -+ -+ -+ -+ -+ -+ Change Password -+ -+ -+ -+ {% include "header.html" %} -+





    -+ -+
    -+ -+ -+
    -+
    -+ -+ -+

    Change your password


    -+
    -+ -+
    -+ -+
    -+
    -+ -+
    -+ -+
    -+ -+
    -+
    -+ -+ -+
    -+ -+
    -+ -+
    -+
    -+

    -+ -+
    -+
    -+
    -+ -+
    -+
    -+ -+ -+
    -+ -+ -+

    -+ {% include "footer.html" %} -+ -+ -+ -+ -+ -diff --git a/ui/profile.html b/ui/profile.html -index cb717ee..59b7397 100644 ---- a/ui/profile.html -+++ b/ui/profile.html -@@ -42,7 +42,10 @@ email : ranihaileydesai@gmail.com -
    -
    -

    --
    -+
    -+ -+ -+
    - - -
    -diff --git a/ui/reset_password.html b/ui/reset_password.html -new file mode 100644 -index 0000000..f154ca2 ---- /dev/null -+++ b/ui/reset_password.html -@@ -0,0 +1,68 @@ -+ -+ -+ -+ -+ -+ -+ Reset Password -+ -+ -+ -+ {% include "header.html" %} -+





    -+ -+
    -+
    -+
    -+
    -+ -+
    -+

    Reset your password


    -+ -+
    -+
    -+
    -+
    -+ -+
    -+
    -+
    -+
    -+ -+ -+
    -+
    -+
    -+
    -+
    -+
    -+
    -+
    -+
    -+
    -+ -+ -+ -+ -+ -+ -+
    -+ -+
    -+ -+ -+
    -+ -+



    -+ {% include "footer.html" %} -+ -+ -+ -+ -+ -diff --git a/webhub/urls.py b/webhub/urls.py -index d65e333..b48a5c3 100644 ---- a/webhub/urls.py -+++ b/webhub/urls.py -@@ -30,6 +30,10 @@ urlpatterns = patterns('', - url(r'^forgot_pass_page/$', views.forgot_pass_page, name='forgot_pass_page'), - url(r'^forgot_pass/$', views.forgot_pass, name='forgot_pass'), - url(r'^verify/$', views.verify, name='verify'), -+ url(r'^reset_pass_page/$', views.reset_pass_page, name='reset_pass_page'), -+ url(r'^change_pass/$', views.change_pass, name='change_pass'), -+ url(r'^change_pass_page/$', views.change_pass_page, name='change_pass_page'), -+ - - ) - -diff --git a/webhub/urls.pyc b/webhub/urls.pyc -index b1d9b7d..9a084e7 100644 -Binary files a/webhub/urls.pyc and b/webhub/urls.pyc differ -diff --git a/webhub/views.py b/webhub/views.py -index 8107072..7e6c0c1 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -383,7 +383,7 @@ def edit_profile(request): - #Forgot Password page call function. - def forgot_pass_page(request): - if request.user.is_authenticated(): -- return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.rider, -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, - "text":'

    Please log out before requesting reset in password.

    \ -

    Click OK to go to the homepage

    ',"link":'/'})) - return HttpResponse(jinja_environ.get_template('forgot_password.html').render({"pcuser":None})) -@@ -409,14 +409,14 @@ def forgot_pass(request): - if user.email <> request.REQUEST['email']: - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'Invalid email. Please go back or click OK to go to the homepage',"link":'/'})) -- user.rider.reset_pass = uuid.uuid4().hex -- user.rider.save() -+ user.pcuser.reset_pass = uuid.uuid4().hex -+ user.pcuser.save() - - subject = "Password Reset Request" -- msg = 'Subject: %s \n\nYou have requested for a password reset on RideBuddy\n\ -+ msg = 'Subject: %s \n\nYou have requested for a password reset on Mobile App Control Center\n\ - Please click on the following link (or copy paste in your browser) to reset your password.\n\n\ - %s/reset_pass_page/?reset_pass=%s&email=%s\n\n\ -- If you have not requested for a reset of password, please ignore.' % (subject, website, user.rider.reset_pass, user.email) -+ If you have not requested for a reset of password, please ignore.' % (subject, website, user.pcuser.reset_pass, user.email) - - x = send_email(msg, user.email) - if x[0] == 0: -@@ -429,6 +429,84 @@ def forgot_pass(request): -

    Click OK to go to the homepage

    ',"link":'/'})) - - -+ -+#Reset Password page call function. -+@csrf_exempt -+def reset_pass_page(request): -+ if request.user.is_authenticated(): -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, -+ "text":'

    Please log out before requesting reset in password.

    \ -+

    Click OK to go to the homepage

    ',"link":'/'})) -+ if "reset_pass" not in request.REQUEST.keys() or 'email' not in request.REQUEST.keys(): -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'

    Invalid Request

    \ -+ Click OK to go to the homepage

    ', "link":'/'})) -+ reset_pass = request.REQUEST['reset_pass'] -+ if reset_pass == "": -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'

    Invalid Request

    \ -+

    click OK to go to the homepage

    ', "link":'/'})) -+ user = Pcuser.objects.filter(reset_pass=reset_pass) -+ if len(user)==0: -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'Invalid Request. Please go back or click OK to go to the homepage',"link":'/'})) -+ -+ user = user[0].user -+ -+ if user.email <> request.REQUEST['email']: -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'Invalid Email. Please go back or click OK to go to the homepage',"link":'/'})) -+ return HttpResponse(jinja_environ.get_template('reset_password.html').render({'pcuser':None, 'reset_pass':reset_pass})) -+ -+ -+ -+#Called when the user clicks change password button. Checks if the previous password is valid or not. -+@csrf_exempt -+def change_pass(request): -+ if "reset_pass" in request.REQUEST.keys(): -+ reset_pass = request.REQUEST['reset_pass'] -+ if reset_pass == "": -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'

    Invalid Request

    \ -+

    click OK to go to the homepage

    ',"link":'/'})) -+ user = Pcuser.objects.filter(reset_pass=reset_pass) -+ if len(user)==0 or 'pass' not in request.REQUEST.keys(): -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'Invalid Request. Please go back or click OK to go to the homepage',"link":'/'})) -+ user = user[0].user -+ user.set_password(request.REQUEST['pass']) -+ user.save() -+ user.pcuser.reset_pass = "" -+ user.pcuser.save() -+ logout(request) -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'Password Changed. Please click OK to go to the homepage and log in again.',"link":'/logout_do/'})) -+ else: -+ retval = check(request) -+ if retval <> None: -+ return retval -+ if "pass" not in request.REQUEST.keys() or "oldpass" not in request.REQUEST.keys(): -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, -+ "text":'Invalid Request. Please go back or click OK to go to the homepage',"link":'/'})) -+ if not request.user.check_password(request.REQUEST['oldpass']): -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, -+ "text":'Invalid Old Password. Click OK to go to the homepage',"link":'/'})) -+ request.user.set_password(request.REQUEST['pass']) -+ request.user.save() -+ logout(request) -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'Password Changed. Please click OK to go to the homepage and log in again.',"link":'/logout_do/'})) -+ -+ -+ -+#Change password page call function -+def change_pass_page(request): -+ retval = check(request) -+ if retval <> None: -+ return retval -+ return HttpResponse(jinja_environ.get_template('change_password.html').render({"pcuser":request.user.pcuser})) -+ -+ - - - #called when user wishes to go to the Peacetrack from dashboard -diff --git a/webhub/views.pyc b/webhub/views.pyc -index 1ebf80a..50e707a 100644 -Binary files a/webhub/views.pyc and b/webhub/views.pyc differ - -commit 7b284e6da683432a36d0cf5f37f20ed3c38bb3b5 -Author: desaivaibhavi -Date: Wed Jun 11 08:41:34 2014 +0000 - - sign up and verification via email working - -diff --git a/ui/forgot_password.html b/ui/forgot_password.html -index e69de29..d7d913f 100644 ---- a/ui/forgot_password.html -+++ b/ui/forgot_password.html -@@ -0,0 +1,70 @@ -+ -+ -+ -+ -+ -+ -+ Forget Password -+ -+ -+ -+ {% include "header.html" %} -+





    -+ -+
    -+ -+
    -+ -+ -+
    -+
    -+

    Forgot Password

    -+

    -+ -+
    -+
    -+
    -+
    -+ -+
    -+
    -+
    -+
    -+ -+
    -+
    -+
    -+
    -+
    -+ -+
    -+
    -+
    -+
    -+
    -+
    -+
    -+ -+
    -+ -+
    -+
    -+ -+
    -+ -+ -+
    -+ -+ -+


    -+ {% include "footer.html" %} -+ -+ -+ -+ -+ -diff --git a/ui/index.html b/ui/index.html -index a970dd9..e408276 100644 ---- a/ui/index.html -+++ b/ui/index.html -@@ -28,7 +28,7 @@ email : ranihaileydesai@gmail.com -

    Password :

    - -
    -- Forgot Password ? -+ Forgot Password ? -

    -

    -

    New User ? Click here to Sign Up !

    -diff --git a/ui/loginverify.html b/ui/loginverify.html -new file mode 100644 -index 0000000..e69de29 -diff --git a/ui/signup.html b/ui/signup.html -index bf94488..3f6eea4 100644 ---- a/ui/signup.html -+++ b/ui/signup.html -@@ -20,7 +20,7 @@ email : ranihaileydesai@gmail.com - -
    -
    --
    -+ -

    Sign Up Form

    -
    - -@@ -37,27 +37,27 @@ email : ranihaileydesai@gmail.com -
    - -

    Username :

    -- -+ -

    Email id :

    -- -+ - - - -

    First name :

    -- -+ -

    Last name :

    -- -+ - - -

    Set Password :

    -- -+ -

    Confirm Password :

    -- -+ - -

    Phone :

    -- -+ -

    Location :

    -- -+ - - - -diff --git a/var.pyc b/var.pyc -new file mode 100644 -index 0000000..f664c9e -Binary files /dev/null and b/var.pyc differ -diff --git a/var.py~ b/var.py~ -new file mode 100644 -index 0000000..e69de29 -diff --git a/webhub/models.py b/webhub/models.py -index 1cb7f65..7bde5b8 100644 ---- a/webhub/models.py -+++ b/webhub/models.py -@@ -24,6 +24,11 @@ class Pcuser(models.Model): - #for reset_password - reset_pass = models.CharField(default="",max_length=320) - -+ #verification status -+ #1 - unverified -+ #any other number = verification code -+ verified = models.CharField(max_length=100) -+ - def __unicode__(self): - return self.user.username - -diff --git a/webhub/models.pyc b/webhub/models.pyc -index 3ac3f74..4c93dc0 100644 -Binary files a/webhub/models.pyc and b/webhub/models.pyc differ -diff --git a/webhub/urls.py b/webhub/urls.py -index d648fe5..d65e333 100644 ---- a/webhub/urls.py -+++ b/webhub/urls.py -@@ -27,7 +27,10 @@ urlpatterns = patterns('', - url(r'^profile/$', views.profile, name='profile'), - url(r'^edit_profile/$', views.edit_profile, name='edit_profile'), - url(r'^edit_profile_page/$', views.edit_profile_page, name='edit_profile_page'), -- -+ url(r'^forgot_pass_page/$', views.forgot_pass_page, name='forgot_pass_page'), -+ url(r'^forgot_pass/$', views.forgot_pass, name='forgot_pass'), -+ url(r'^verify/$', views.verify, name='verify'), -+ - ) - - -diff --git a/webhub/urls.pyc b/webhub/urls.pyc -index 9c773b1..b1d9b7d 100644 -Binary files a/webhub/urls.pyc and b/webhub/urls.pyc differ -diff --git a/webhub/views.py b/webhub/views.py -index eacd5d5..8107072 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -12,10 +12,19 @@ from django.contrib import auth - from django.contrib.auth import authenticate, login, logout - from django.core.context_processors import csrf - from django.views.decorators.csrf import csrf_exempt -+from django.contrib.auth.models import User - import jinja2 -+import uuid - from jinja2.ext import loopcontrols - from webhub.checker import check - from webhub.models import * -+import smtplib -+ -+#SMTP port for sending emails -+SMTP_PORT = 465 -+ -+#link for the localhost -+website = "http://192.168.33.10:8000" - - jinja_environ = jinja2.Environment(loader=jinja2.FileSystemLoader(['ui']), extensions=[loopcontrols]) - -@@ -87,19 +96,18 @@ def signup_do(request): - if first_name == "": - first_name = username - -- try: -- user = User.objects.create_user(username, email, password) -- user.first_name = first_name -- user.last_name = last_name -- user.save() -- entry = Pcuser(user=user, phone=phone, gender=gender, location=location, verified = uuid.uuid4().hex) -+ user = User.objects.create_user(username, email, password) -+ user.first_name = first_name -+ user.last_name = last_name -+ user.save() -+ entry = Pcuser(user=user, phone=phone, gender=gender, location=location, verified = uuid.uuid4().hex) - -- entry.save() -- #send email to user -- login_do(request) -- return send_verification_email(request) -- except Exception as e: -- return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ entry.save() -+ #send email to user -+ login_do(request) -+ send_verification_email(request) -+ -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'

    Username already exists. Please enter some other username.

    Go Back or click OK to go to signup page.

    ',"link":'/signup_page/'})) - - -@@ -113,7 +121,7 @@ def send_verification_email(request): - request.user.pcuser - except: - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -- "text":'No Rider associated!. Please go back or click to go to the homepage' , "link": '/'})) -+ "text":'No Pcuser associated!. Please go back or click to go to the homepage' , "link": '/'})) - entry=request.user - subject = 'Peace Corps Verification Email' - msg = 'Subject: %s \n\nYour email has been registered on pchub.com.\nPlease\ -@@ -128,7 +136,7 @@ def send_verification_email(request): - - - --#Function to send emails using google smtplib. Takes email id and message as input. -+#Function to send emails using google smtplib. Takes email id and message as input. - def send_email(msg, email): - gmailLogin = 'ranipc93' - gmailPas = 'ranipc1993' -@@ -142,9 +150,35 @@ def send_email(msg, email): - return (1,1) - - -- -- -+#Called when a user enters verification code and clicks on submit. Checks the verification code with database. -+def verify(request): -+ if not request.user.is_authenticated(): -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'Verification Successful. Go to homepage' , "link": '/'})) -+# return HttpResponse(jinja_environ.get_template('index.html').render({"pcuser":Non, -+# "code":request.REQUEST['code']})) -+# index(request) -+ try: -+ request.user.pcuser -+ except: -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'

    No Pcuser associated.

    Please go back or click OK to go to the homepage

    ',"link":'/'})) -+ -+ code = request.REQUEST['code'] -+ pcuser = request.user.pcuser -+ if pcuser.verified == '1': -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, -+ "text":'

    Verification successful.

    Click OK to go to the homepage

    ',"link":'/'})) -+ elif code == pcuser.verified: -+ pcuser.verified = '1' -+ pcuser.save() -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, -+ "text":'

    Verification successful.

    Click OK to go to the homepage

    ',"link":'/'})) - -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, -+ "text":'

    Verification Failed.

    Please go back or click OK to go to the homepage

    ',"link":'/'})) -+ -+ - - - #Called when a user clicks login button. -@@ -346,6 +380,56 @@ def edit_profile(request): - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, - "text":'Profile edit successful.',"text1":'Click here to view the profile.',"link":'/profile/?id='+ str(request.user.pcuser.id)})) - -+#Forgot Password page call function. -+def forgot_pass_page(request): -+ if request.user.is_authenticated(): -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.rider, -+ "text":'

    Please log out before requesting reset in password.

    \ -+

    Click OK to go to the homepage

    ',"link":'/'})) -+ return HttpResponse(jinja_environ.get_template('forgot_password.html').render({"pcuser":None})) -+ -+ -+ -+ -+#Called when the user clicks forgot password after the data is validated. This sends a verification mail to the user. -+@csrf_exempt -+def forgot_pass(request): -+ if request.user.is_authenticated(): -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'

    Please log out in order to request for a password reset.

    \ -+

    Please go back or click OK to go to the homepage

    ',"link":'/'})) -+ if 'username' not in request.REQUEST.keys() or 'email' not in request.REQUEST.keys(): -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'Invalid Request. Please go back or click OK to go to the homepage',"link":'/'})) -+ user = User.objects.filter(username=request.REQUEST['username']) -+ if len(user) == 0: -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'User Does not exist. Please go back or click OK to go to the homepage',"link":'/'})) -+ user = user[0] -+ if user.email <> request.REQUEST['email']: -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'Invalid email. Please go back or click OK to go to the homepage',"link":'/'})) -+ user.rider.reset_pass = uuid.uuid4().hex -+ user.rider.save() -+ -+ subject = "Password Reset Request" -+ msg = 'Subject: %s \n\nYou have requested for a password reset on RideBuddy\n\ -+ Please click on the following link (or copy paste in your browser) to reset your password.\n\n\ -+ %s/reset_pass_page/?reset_pass=%s&email=%s\n\n\ -+ If you have not requested for a reset of password, please ignore.' % (subject, website, user.rider.reset_pass, user.email) -+ -+ x = send_email(msg, user.email) -+ if x[0] == 0: -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'Could not process request, please try again later by going back or clicking OK to go to the homepage', "link":'/'})) -+ else: -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'

    An email has been sent to your regestered email address.

    \ -+

    Check your email and click on the link to reset your password.

    \ -+

    Click OK to go to the homepage

    ',"link":'/'})) -+ -+ -+ - - #called when user wishes to go to the Peacetrack from dashboard - def peacetrack(request): -diff --git a/webhub/views.pyc b/webhub/views.pyc -index 8fce999..1ebf80a 100644 -Binary files a/webhub/views.pyc and b/webhub/views.pyc differ - -commit da115ac70e371bed075e302d18c42bd3f148e4c2 -Author: desaivaibhavi -Date: Mon Jun 9 20:29:51 2014 +0530 - - forgot password, sign up added - -diff --git a/ui/forgot_password.html b/ui/forgot_password.html -new file mode 100644 -index 0000000..e69de29 -diff --git a/ui/index.html b/ui/index.html -index 5c0209b..a970dd9 100644 ---- a/ui/index.html -+++ b/ui/index.html -@@ -18,7 +18,7 @@ email : ranihaileydesai@gmail.com - -
    - --
    -+
    -
    - -

    Log in

    -@@ -27,8 +27,11 @@ email : ranihaileydesai@gmail.com - -

    Password :

    - -+
    -+ Forgot Password ? -

    -- -+

    -+

    New User ? Click here to Sign Up !

    - -

    -
    -diff --git a/ui/signup.html b/ui/signup.html -new file mode 100644 -index 0000000..bf94488 ---- /dev/null -+++ b/ui/signup.html -@@ -0,0 +1,79 @@ -+ -+ -+ -+ -+ -+ -+ Sign Up -+ -+ -+ -+ {% include "header.html" %} -+





    -+ -+
    -+ -+
    -+
    -+
    -+

    Sign Up Form

    -+
    -+ -+ -+ -+
    -+ -+ -+
    -+ -+

    Username :

    -+ -+

    Email id :

    -+ -+ -+ -+ -+

    First name :

    -+ -+

    Last name :

    -+ -+ -+ -+

    Set Password :

    -+ -+

    Confirm Password :

    -+ -+ -+

    Phone :

    -+ -+

    Location :

    -+ -+ -+ -+ -+

    -+

    -+ -+
    -+

    -+
    -+ -+
    -+ -+





    -+ {% include "footer.html" %} -+ -+ -+ -+ -+ -diff --git a/webhub/models.pyc b/webhub/models.pyc -index 4481dbc..3ac3f74 100644 -Binary files a/webhub/models.pyc and b/webhub/models.pyc differ -diff --git a/webhub/urls.py b/webhub/urls.py -index 483c89c..d648fe5 100644 ---- a/webhub/urls.py -+++ b/webhub/urls.py -@@ -10,6 +10,10 @@ from webhub import views - urlpatterns = patterns('', - url(r'^index/$', views.index, name='index'), - url(r'^$', views.dashboard, name='dashboard'), -+ url(r'^signup_page/$', views.signup_page, name='signup_page'), -+ url(r'^signup_do/$', views.signup_do, name='signup_do'), -+ url(r'^send_verification_email/$', views.send_verification_email, name='send_verification_email'), -+ url(r'^send_email/$', views.send_email, name='send_email'), - url(r'^login_do/$', views.login_do, name='login_do'), - url(r'^logout_do/$', views.logout_do, name='logout_do'), - url(r'^malaria/$', views.malaria, name='malaria'), -diff --git a/webhub/urls.pyc b/webhub/urls.pyc -index 49ebb98..9c773b1 100644 -Binary files a/webhub/urls.pyc and b/webhub/urls.pyc differ -diff --git a/webhub/views.py b/webhub/views.py -index f22fd6c..eacd5d5 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -35,6 +35,118 @@ def dashboard(request): - return HttpResponse(jinja_environ.get_template('dashboard.html').render(template_values)) - - -+#Calls the signup page. If the user us already logged in, s/he will be redirected to dashboard. -+def signup_page(request): -+ if request.user.is_authenticated(): -+ redirect_url = "/" -+ if 'redirect_url' in request.REQUEST.keys(): -+ redirect_url = request.REQUEST['redirect_url'] -+ return HttpResponse(jinja_environ.get_template('redirect.html').render({"pcuser":None,"redirect_url":redirect_url})) -+ -+ else: -+ return HttpResponse(jinja_environ.get_template('signup.html').render({"pcuser":None})) -+ -+ -+#Called when a user clicks submit button in signup. Here a verification mail is also sent to the user. -+@csrf_exempt -+def signup_do(request): -+ if request.user.is_authenticated(): -+ logout(request) -+ redirect_url = "/" -+ if 'redirect_url' in request.REQUEST.keys(): -+ redirect_url = request.REQUEST['redirect_url'] -+ return HttpResponse(jinja_environ.get_template('redirect.html').render({"pcuser":None,"redirect_url":redirect_url})) -+ -+ username = request.REQUEST['username'] -+ password = request.REQUEST['password'] -+ confirmpassword = request.REQUEST['confirmpassword'] -+ -+ if password <> confirmpassword: -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'

    Passwords don\'t match. Please Enter again.

    Click OK to go back to signup page.

    ',"link":'/signup_page/'})) -+ -+ first_name = request.REQUEST['first_name'] -+ last_name = request.REQUEST['last_name'] -+ phone = request.REQUEST['phone'] -+ email = request.REQUEST['email'] -+ gender = request.REQUEST['gender'] -+ location = request.REQUEST['location'] -+ -+ try: -+ if len(User.objects.filter(email=email))<>0: -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'

    Someone has already registered using this email.

    If you have forgotten your password, click

    Click here to go back to signup page.

    ',"link":'0'})) -+ except: -+ pass -+ -+ if '@' not in email or '.' not in email: -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'

    Invalid email, please Enter again.

    Go Back or click OK to go to signup page.

    ',"link":"/signup_page/"})) -+ -+ -+ if first_name == "": -+ first_name = username -+ -+ try: -+ user = User.objects.create_user(username, email, password) -+ user.first_name = first_name -+ user.last_name = last_name -+ user.save() -+ entry = Pcuser(user=user, phone=phone, gender=gender, location=location, verified = uuid.uuid4().hex) -+ -+ entry.save() -+ #send email to user -+ login_do(request) -+ return send_verification_email(request) -+ except Exception as e: -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'

    Username already exists. Please enter some other username.

    Go Back or click OK to go to signup page.

    ',"link":'/signup_page/'})) -+ -+ -+ -+#Function to send verification mail to user's email after he signs up. -+def send_verification_email(request): -+ if not request.user.is_authenticated(): -+ return HttpResponse(jinja_environ.get_template('index.html').render({"pcuser":None})) -+ -+ try: -+ request.user.pcuser -+ except: -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'No Rider associated!. Please go back or click to go to the homepage' , "link": '/'})) -+ entry=request.user -+ subject = 'Peace Corps Verification Email' -+ msg = 'Subject: %s \n\nYour email has been registered on pchub.com.\nPlease\ -+ click on the following link to verify (or copy paste it in your browser if needed)\n\n\ -+ %s/verify?code=%s\n\nIf you have not registered on our website, please ignore.' % (subject, website, entry.pcuser.verified) -+ -+ x = send_email(msg, entry.email) -+ if x[0]==0: -+ return x[1] -+ -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, "text":'

    Verification Email sent! Please Check your email inbox.

    To re-send verification email, click here.

    Click here to go to the homepage and log-in again

    ', "link":'0'})) -+ -+ -+ -+#Function to send emails using google smtplib. Takes email id and message as input. -+def send_email(msg, email): -+ gmailLogin = 'ranipc93' -+ gmailPas = 'ranipc1993' -+ fro = gmailLogin + "@gmail.com" -+ -+ to = email -+ -+ server = smtplib.SMTP_SSL('smtp.googlemail.com',SMTP_PORT) -+ a = server.login( gmailLogin, gmailPas) -+ server.sendmail(fro, to,msg) -+ return (1,1) -+ -+ -+ -+ -+ -+ -+ - #Called when a user clicks login button. - @csrf_exempt - def login_do(request): -diff --git a/webhub/views.pyc b/webhub/views.pyc -index d4598c2..8fce999 100644 -Binary files a/webhub/views.pyc and b/webhub/views.pyc differ - -commit 3172c62867a94f17298fee28d8bc76a212882bc0 -Author: desaivaibhavi -Date: Fri Jun 6 22:24:43 2014 +0000 - - rev history - -diff --git a/ui/viewpost.html b/ui/viewpost.html -index ff9a121..5962859 100644 ---- a/ui/viewpost.html -+++ b/ui/viewpost.html -@@ -51,13 +51,21 @@ email : ranihaileydesai@gmail.com -
    -
    -
    --


    --

    Revision History

    --

    The post was created by {{post.owner}} on {{post.created}}

    -- {% for rev in revpostobj %} --

    The post was updated by {{rev.owner_rev.user.first_name}} on {{rev.created}}

    -- {% endfor %} -+

    -+

    Revision History of this Post


    - -+
    -+
    -+
    -+
    -+

    The post was created by {{post.owner}} on {{post.created}}


    -+ {% for rev in revpostobj %} -+

    The post was updated by {{rev.owner_rev.user.first_name}} on {{rev.created}}

    -+ {% endfor %} -+
    -+
    -+
    -+
    -
    - - -diff --git a/webhub/models.pyc b/webhub/models.pyc -index 1f63bca..4481dbc 100644 -Binary files a/webhub/models.pyc and b/webhub/models.pyc differ -diff --git a/webhub/views.pyc b/webhub/views.pyc -index 6f25890..d4598c2 100644 -Binary files a/webhub/views.pyc and b/webhub/views.pyc differ - -commit a94429012a0c428603f097c1f0953c0e589252bb -Author: desaivaibhavi -Date: Fri Jun 6 21:05:17 2014 +0000 - - comment and code cleaning - -diff --git a/webhub/models.py b/webhub/models.py -index 0305e60..1cb7f65 100644 ---- a/webhub/models.py -+++ b/webhub/models.py -@@ -37,26 +37,28 @@ class Post(models.Model): - title_post = models.CharField(max_length=300) - #description - description_post = models.CharField(max_length=2000) -- -+ #field to note the timestamp when the post was created - created = models.DateTimeField(auto_now_add=True) -+ #field to note the timestamp when the post was last updated - updated = models.DateTimeField(auto_now=True) - - def __unicode__(self): - return self.owner.user.username - --#Post table stores details about revision history posts -+#Post table stores details about revision history of edit of the posts - - class RevPost(models.Model): -- #The owner of the post -+ #The post which is being edited - owner_rev_post = models.ForeignKey(Post, null=False, related_name='owner_rev_post') -+ #The user who is editing the post - owner_rev = models.ForeignKey(Pcuser, null=False, related_name='owner_rev') - #revised title - title_post_rev = models.CharField(max_length=300) - #revised description - description_post_rev = models.CharField(max_length=2000) -- -+ #field to note the timestamp when the revised version was created - created = models.DateTimeField(auto_now_add=True) -- updated = models.DateTimeField(auto_now=True) -+ - - def __unicode__(self): - return self.owner.user.username -diff --git a/webhub/views.py b/webhub/views.py -index 49c967c..f22fd6c 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -73,7 +73,7 @@ def malaria(request): - all_posts = Post.objects.all() - return HttpResponse(jinja_environ.get_template('malaria.html').render({"all_posts":all_posts, "pcuser":request.user.pcuser})) - --#called when a user wants to view a particular post. -+#called when a user wants to view a particular post. Also shows up the revision history - def view_post(request): - retval = check(request) - if retval <> None: -@@ -85,6 +85,7 @@ def view_post(request): - postobj=Post.objects.get(id=key) - - revpostobj = RevPost.objects.filter(owner_rev_post_id=key) -+ - return HttpResponse(jinja_environ.get_template('viewpost.html').render({"pcuser":request.user.pcuser, 'post':postobj, 'revpostobj':revpostobj})) - except Exception as e: - return HttpResponse(e) -@@ -131,7 +132,7 @@ def edit_post_page(request): - except Exception as e: - return HttpResponse(e) - --#Called when a user edits his/her post. -+#Called when a user edits his/her post and also saves the revision history - @csrf_exempt - def edit_post(request): - retval = check(request) - -commit d6413796756050efc16490cf0c0e81f4d2a9f370 -Author: desaivaibhavi -Date: Fri Jun 6 20:58:26 2014 +0000 - - revision history added - -diff --git a/ui/viewpost.html b/ui/viewpost.html -index a2d6079..ff9a121 100644 ---- a/ui/viewpost.html -+++ b/ui/viewpost.html -@@ -54,9 +54,9 @@ email : ranihaileydesai@gmail.com -


    -

    Revision History

    -

    The post was created by {{post.owner}} on {{post.created}}

    --

    The post was updated by {{post.owner}} on {{post.updated}}

    -- See the edits -- abcd changed to -> cdef -+ {% for rev in revpostobj %} -+

    The post was updated by {{rev.owner_rev.user.first_name}} on {{rev.created}}

    -+ {% endfor %} - -
    - -diff --git a/webhub/models.py b/webhub/models.py -index 73b78c2..0305e60 100644 ---- a/webhub/models.py -+++ b/webhub/models.py -@@ -42,4 +42,21 @@ class Post(models.Model): - updated = models.DateTimeField(auto_now=True) - - def __unicode__(self): -- return self.owner.user.username -\ No newline at end of file -+ return self.owner.user.username -+ -+#Post table stores details about revision history posts -+ -+class RevPost(models.Model): -+ #The owner of the post -+ owner_rev_post = models.ForeignKey(Post, null=False, related_name='owner_rev_post') -+ owner_rev = models.ForeignKey(Pcuser, null=False, related_name='owner_rev') -+ #revised title -+ title_post_rev = models.CharField(max_length=300) -+ #revised description -+ description_post_rev = models.CharField(max_length=2000) -+ -+ created = models.DateTimeField(auto_now_add=True) -+ updated = models.DateTimeField(auto_now=True) -+ -+ def __unicode__(self): -+ return self.owner.user.username -diff --git a/webhub/models.pyc b/webhub/models.pyc -index 4ac70d1..1f63bca 100644 -Binary files a/webhub/models.pyc and b/webhub/models.pyc differ -diff --git a/webhub/urls.py b/webhub/urls.py -index b04ff07..483c89c 100644 ---- a/webhub/urls.py -+++ b/webhub/urls.py -@@ -23,6 +23,7 @@ urlpatterns = patterns('', - url(r'^profile/$', views.profile, name='profile'), - url(r'^edit_profile/$', views.edit_profile, name='edit_profile'), - url(r'^edit_profile_page/$', views.edit_profile_page, name='edit_profile_page'), -+ - ) - - -diff --git a/webhub/urls.pyc b/webhub/urls.pyc -index f3ecc38..49ebb98 100644 -Binary files a/webhub/urls.pyc and b/webhub/urls.pyc differ -diff --git a/webhub/views.py b/webhub/views.py -index 0dd5695..49c967c 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -83,7 +83,9 @@ def view_post(request): - pcuser=request.user.pcuser - key=request.REQUEST['key'] - postobj=Post.objects.get(id=key) -- return HttpResponse(jinja_environ.get_template('viewpost.html').render({"pcuser":request.user.pcuser, 'post':postobj})) -+ -+ revpostobj = RevPost.objects.filter(owner_rev_post_id=key) -+ return HttpResponse(jinja_environ.get_template('viewpost.html').render({"pcuser":request.user.pcuser, 'post':postobj, 'revpostobj':revpostobj})) - except Exception as e: - return HttpResponse(e) - -@@ -139,11 +141,19 @@ def edit_post(request): - owner = request.user.pcuser - postid = request.REQUEST['postid'] - postobj = None -+ revpostobj = None - try: - postobj = Post.objects.get(pk=postid) - except Exception as e: - return HttpResponse(e) - -+ entry = RevPost(owner_rev=owner, -+ owner_rev_post=postobj, -+ title_post_rev=postobj.title_post, -+ description_post_rev=postobj.description_post, -+ ) -+ entry.save() -+ - title_post = request.REQUEST['title'] - description_post = request.REQUEST['description'] - -@@ -157,6 +167,8 @@ def edit_post(request): - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, - "text":'Post edited successfully.',"text1":'Click here to view post.', "link": '/view_post/?key=' + str(postobj.id)})) - -+ -+ - #Called when a user cancels his post. - @csrf_exempt - def delete_post(request): -@@ -221,6 +233,7 @@ def edit_profile(request): - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, - "text":'Profile edit successful.',"text1":'Click here to view the profile.',"link":'/profile/?id='+ str(request.user.pcuser.id)})) - -+ - #called when user wishes to go to the Peacetrack from dashboard - def peacetrack(request): - return HttpResponse(jinja_environ.get_template('peacetrack.html').render({"pcuser":None})) -diff --git a/webhub/views.pyc b/webhub/views.pyc -index 0fae71a..6f25890 100644 -Binary files a/webhub/views.pyc and b/webhub/views.pyc differ - -commit 1f0425bad6c2dadb9048c53b9ef4e582f7aa0b84 -Author: desaivaibhavi -Date: Fri Jun 6 09:22:01 2014 +0000 - - revision history module started - -diff --git a/ui/viewpost.html b/ui/viewpost.html -index c85ab3c..a2d6079 100644 ---- a/ui/viewpost.html -+++ b/ui/viewpost.html -@@ -50,6 +50,15 @@ email : ranihaileydesai@gmail.com - -
    -
    -+
    -+


    -+

    Revision History

    -+

    The post was created by {{post.owner}} on {{post.created}}

    -+

    The post was updated by {{post.owner}} on {{post.updated}}

    -+ See the edits -+ abcd changed to -> cdef -+ -+
    - - - -diff --git a/webhub/views.py b/webhub/views.py -index b952a54..0dd5695 100644 ---- a/webhub/views.py -+++ b/webhub/views.py -@@ -223,4 +223,5 @@ def edit_profile(request): - - #called when user wishes to go to the Peacetrack from dashboard - def peacetrack(request): -- return HttpResponse(jinja_environ.get_template('peacetrack.html').render({"pcuser":None})) -\ No newline at end of file -+ return HttpResponse(jinja_environ.get_template('peacetrack.html').render({"pcuser":None})) -+ -diff --git a/webhub/views.pyc b/webhub/views.pyc -index ada3218..0fae71a 100644 -Binary files a/webhub/views.pyc and b/webhub/views.pyc differ - -commit 94edc2b6765f77548a8e1d0df8190e0692436237 -Author: desaivaibhavi -Date: Thu Jun 5 20:59:36 2014 +0000 - - model updated for implementing the revision history - -diff --git a/infohub/settings.pyc b/infohub/settings.pyc -index 4d2a608..8a1fa8f 100644 -Binary files a/infohub/settings.pyc and b/infohub/settings.pyc differ -diff --git a/infohub/urls.pyc b/infohub/urls.pyc -index 41b429f..5d9e22c 100644 -Binary files a/infohub/urls.pyc and b/infohub/urls.pyc differ -diff --git a/infohub/wsgi.pyc b/infohub/wsgi.pyc -index af5136b..44f17e1 100644 -Binary files a/infohub/wsgi.pyc and b/infohub/wsgi.pyc differ -diff --git a/ui/viewpost.html b/ui/viewpost.html -index 5951d47..c85ab3c 100644 ---- a/ui/viewpost.html -+++ b/ui/viewpost.html -@@ -16,9 +16,9 @@ email : ranihaileydesai@gmail.com -





    - -

    Malaria : infoHub

    -- -
    -
    -+ -

    View Post

    -
    - -diff --git a/webhub/models.py b/webhub/models.py -index b1e78c1..73b78c2 100644 ---- a/webhub/models.py -+++ b/webhub/models.py -@@ -38,5 +38,8 @@ class Post(models.Model): - #description - description_post = models.CharField(max_length=2000) - -+ created = models.DateTimeField(auto_now_add=True) -+ updated = models.DateTimeField(auto_now=True) -+ - def __unicode__(self): - return self.owner.user.username -\ No newline at end of file -diff --git a/webhub/models.pyc b/webhub/models.pyc -index 4af902e..4ac70d1 100644 -Binary files a/webhub/models.pyc and b/webhub/models.pyc differ - -commit 2ed39792000156db7a6a77a0c730c5a25110872f -Author: desaivaibhavi -Date: Thu Jun 5 11:45:37 2014 +0000 - - time zone updated - -diff --git a/infohub/settings.py b/infohub/settings.py -index 5a9778b..6dba49a 100644 ---- a/infohub/settings.py -+++ b/infohub/settings.py -@@ -67,7 +67,7 @@ DATABASES = { - - LANGUAGE_CODE = 'en-us' - --TIME_ZONE = 'Asia/Kolkata' -+TIME_ZONE = 'America/Chicago' - - USE_I18N = True - - -commit 038d5b76d3f2a8b4e0ae286744738eba1e53b9a2 -Author: desaivaibhavi -Date: Thu Jun 5 11:34:09 2014 +0000 - - updated readme file - -diff --git a/readmeForCode b/readmeForCode -index 9acc923..4e28fe7 100644 ---- a/readmeForCode -+++ b/readmeForCode -@@ -29,9 +29,9 @@ To run the application, - 4. You might be asked to create a super user. Create one. - 5. Runnning the server : run the following command from the terminal - python manage.py runserver 0.0.0.0:8000 --6. Open the web-browser and go to http://192.168.33.10:8000/admin. Log in. -+6. Open the web-browser and go to http://192.168.33.10:8000/admin. Log in (with the superuser credentials). - 7. You will have to create one user from the admin panel.Create one user and add it to the new pcuser. Log out. --8. Now go to http://192.168.33.10:8000/ -+8. Now go to http://192.168.33.10:8000/. Login with the credential of the pcuser that you created from the admin panel. - 9. Done ! - - -diff --git a/readmeForCode~ b/readmeForCode~ -index 1a2c8df..4e28fe7 100644 ---- a/readmeForCode~ -+++ b/readmeForCode~ -@@ -3,6 +3,7 @@ Readme file : - Details about the folders - - infohub : contains the python environment setup, it contains 4 files - init.py, settings.py, urls.py and wsgi.py -+settings.py has the main configuration settings like dependencies, database, timezone etc. - - ui : contains the ui page templates of the site, it conains the html,css, js page templates with applied jinja integration. Also, I have used bootstrap for responsiveness and better UI design. - -@@ -28,9 +29,9 @@ To run the application, - 4. You might be asked to create a super user. Create one. - 5. Runnning the server : run the following command from the terminal - python manage.py runserver 0.0.0.0:8000 --6. Open the web-browser and go to http://192.168.33.10:8000/admin. Log in. -+6. Open the web-browser and go to http://192.168.33.10:8000/admin. Log in (with the superuser credentials). - 7. You will have to create one user from the admin panel.Create one user and add it to the new pcuser. Log out. --8. Now go to http://192.168.33.10:8000/ -+8. Now go to http://192.168.33.10:8000/. Login with the credential of the pcuser that you created from the admin panel. - 9. Done ! - - - -commit c97680a14315e7288aa0969dbc99c27f1bba3af4 -Author: desaivaibhavi -Date: Thu Jun 5 11:28:40 2014 +0000 - - readme file added for the code - -diff --git a/readmeForCode b/readmeForCode -new file mode 100644 -index 0000000..9acc923 ---- /dev/null -+++ b/readmeForCode -@@ -0,0 +1,37 @@ -+Readme file : -+ -+Details about the folders -+ -+infohub : contains the python environment setup, it contains 4 files - init.py, settings.py, urls.py and wsgi.py -+settings.py has the main configuration settings like dependencies, database, timezone etc. -+ -+ui : contains the ui page templates of the site, it conains the html,css, js page templates with applied jinja integration. Also, I have used bootstrap for responsiveness and better UI design. -+ -+webhub : contains the python-django backend of the site, it conains 7 files - init.py, admin.py, checker.py, models.py, tests.py, urls.py and views.py -+admin.py contains the models that are to be added in the admin panel -+checker.py has a check function that redirects the user to the home page depending upon his current status (i.e. login/logout) -+models.py has all the information about the models we are going to have in the database -+urls.py has the urls of the pages created connected with the respective views -+views.py has all the views, ie function to call different views and render the respective values from the backend -+ -+manage.py : is the file that is used to run the application -+ -+ -+Guidelines to run the application : -+ -+I had to reinstall postgres and python on the VM provided. Also, I had to install python-psycopg2 and jinja on the VM. Make sure the internet is working as I have used some online resources right now. -+ -+To run the application, -+1. Start the VM. Install the mentioned dependencies if required -+2. Go to the directory which has manage.py file -+3. Syncing with the database : run the following command from the terminal -+ python manage.py syncdb -+4. You might be asked to create a super user. Create one. -+5. Runnning the server : run the following command from the terminal -+ python manage.py runserver 0.0.0.0:8000 -+6. Open the web-browser and go to http://192.168.33.10:8000/admin. Log in. -+7. You will have to create one user from the admin panel.Create one user and add it to the new pcuser. Log out. -+8. Now go to http://192.168.33.10:8000/ -+9. Done ! -+ -+ -diff --git a/readmeForCode~ b/readmeForCode~ -new file mode 100644 -index 0000000..1a2c8df ---- /dev/null -+++ b/readmeForCode~ -@@ -0,0 +1,36 @@ -+Readme file : -+ -+Details about the folders -+ -+infohub : contains the python environment setup, it contains 4 files - init.py, settings.py, urls.py and wsgi.py -+ -+ui : contains the ui page templates of the site, it conains the html,css, js page templates with applied jinja integration. Also, I have used bootstrap for responsiveness and better UI design. -+ -+webhub : contains the python-django backend of the site, it conains 7 files - init.py, admin.py, checker.py, models.py, tests.py, urls.py and views.py -+admin.py contains the models that are to be added in the admin panel -+checker.py has a check function that redirects the user to the home page depending upon his current status (i.e. login/logout) -+models.py has all the information about the models we are going to have in the database -+urls.py has the urls of the pages created connected with the respective views -+views.py has all the views, ie function to call different views and render the respective values from the backend -+ -+manage.py : is the file that is used to run the application -+ -+ -+Guidelines to run the application : -+ -+I had to reinstall postgres and python on the VM provided. Also, I had to install python-psycopg2 and jinja on the VM. Make sure the internet is working as I have used some online resources right now. -+ -+To run the application, -+1. Start the VM. Install the mentioned dependencies if required -+2. Go to the directory which has manage.py file -+3. Syncing with the database : run the following command from the terminal -+ python manage.py syncdb -+4. You might be asked to create a super user. Create one. -+5. Runnning the server : run the following command from the terminal -+ python manage.py runserver 0.0.0.0:8000 -+6. Open the web-browser and go to http://192.168.33.10:8000/admin. Log in. -+7. You will have to create one user from the admin panel.Create one user and add it to the new pcuser. Log out. -+8. Now go to http://192.168.33.10:8000/ -+9. Done ! -+ -+ - -commit 56334a5fd0488d8569d59fce510d62021fe57a59 -Author: desaivaibhavi -Date: Thu Jun 5 11:07:24 2014 +0000 - - author details added - -diff --git a/infohub/settings.py b/infohub/settings.py -index 8d4e795..5a9778b 100644 ---- a/infohub/settings.py -+++ b/infohub/settings.py -@@ -1,12 +1,7 @@ --""" --Django settings for infohub project. -- --For more information on this file, see --https://docs.djangoproject.com/en/1.6/topics/settings/ -- --For the full list of settings and their values, see --https://docs.djangoproject.com/en/1.6/ref/settings/ --""" -+#Version : Phython/Django 2.7.6, PostgreSQL 9.3.4 -+#Author : Vaibhavi Desai -+#Github username : desaivaibhavi -+#email : ranihaileydesai@gmail.com - - # Build paths inside the project like this: os.path.join(BASE_DIR, ...) - import os -diff --git a/infohub/urls.py b/infohub/urls.py -index 8a0bde5..3de6cd4 100644 ---- a/infohub/urls.py -+++ b/infohub/urls.py -@@ -1,3 +1,8 @@ -+#Version : Phython/Django 2.7.6, PostgreSQL 9.3.4 -+#Author : Vaibhavi Desai -+#Github username : desaivaibhavi -+#email : ranihaileydesai@gmail.com -+ - from django.conf.urls import patterns, include, url - - from django.contrib import admin -diff --git a/infohub/wsgi.py b/infohub/wsgi.py -index 8d0bb50..eb69fe2 100644 ---- a/infohub/wsgi.py -+++ b/infohub/wsgi.py -@@ -1,11 +1,7 @@ --""" --WSGI config for infohub project. -- --It exposes the WSGI callable as a module-level variable named ``application``. -- --For more information on this file, see --https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/ --""" -+#Version : Phython/Django 2.7.6, PostgreSQL 9.3.4 -+#Author : Vaibhavi Desai -+#Github username : desaivaibhavi -+#email : ranihaileydesai@gmail.com - - import os - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "infohub.settings") - -commit 7f3186347a390b94c34feb32eab10276fa47f86b -Author: desaivaibhavi -Date: Thu Jun 5 11:01:51 2014 +0000 - - initial commit - -diff --git a/infohub/__init__.py b/infohub/__init__.py -new file mode 100644 -index 0000000..e69de29 -diff --git a/infohub/__init__.pyc b/infohub/__init__.pyc -new file mode 100644 -index 0000000..5a0a487 -Binary files /dev/null and b/infohub/__init__.pyc differ -diff --git a/infohub/settings.py b/infohub/settings.py -new file mode 100644 -index 0000000..8d4e795 ---- /dev/null -+++ b/infohub/settings.py -@@ -0,0 +1,87 @@ -+""" -+Django settings for infohub project. -+ -+For more information on this file, see -+https://docs.djangoproject.com/en/1.6/topics/settings/ -+ -+For the full list of settings and their values, see -+https://docs.djangoproject.com/en/1.6/ref/settings/ -+""" -+ -+# Build paths inside the project like this: os.path.join(BASE_DIR, ...) -+import os -+BASE_DIR = os.path.dirname(os.path.dirname(__file__)) -+ -+ -+# Quick-start development settings - unsuitable for production -+# See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/ -+ -+# SECURITY WARNING: keep the secret key used in production secret! -+SECRET_KEY = '@0kjw@u5rv7mf!s2j8ix7lq@n%w&v$6p8ku%8hkmmxxj$w44ys' -+ -+# SECURITY WARNING: don't run with debug turned on in production! -+DEBUG = True -+ -+TEMPLATE_DEBUG = True -+ -+ALLOWED_HOSTS = [] -+ -+ -+# Application definition -+ -+INSTALLED_APPS = ( -+ 'django.contrib.admin', -+ 'django.contrib.auth', -+ 'django.contrib.contenttypes', -+ 'django.contrib.sessions', -+ 'django.contrib.messages', -+ 'django.contrib.staticfiles', -+ 'webhub', -+) -+ -+MIDDLEWARE_CLASSES = ( -+ 'django.contrib.sessions.middleware.SessionMiddleware', -+ 'django.middleware.common.CommonMiddleware', -+ 'django.middleware.csrf.CsrfViewMiddleware', -+ 'django.contrib.auth.middleware.AuthenticationMiddleware', -+ 'django.contrib.messages.middleware.MessageMiddleware', -+ 'django.middleware.clickjacking.XFrameOptionsMiddleware', -+) -+ -+ROOT_URLCONF = 'infohub.urls' -+ -+WSGI_APPLICATION = 'infohub.wsgi.application' -+ -+ -+# Database -+# https://docs.djangoproject.com/en/1.6/ref/settings/#databases -+ -+DATABASES = { -+ 'default': { -+ 'ENGINE': 'django.db.backends.postgresql_psycopg2', -+ 'NAME': 'postgres', -+ 'USER': 'postgres', -+ 'PASSWORD': 'rani', -+ 'HOST': '0.0.0.0', -+ 'PORT': '5432', -+ } -+} -+ -+# Internationalization -+# https://docs.djangoproject.com/en/1.6/topics/i18n/ -+ -+LANGUAGE_CODE = 'en-us' -+ -+TIME_ZONE = 'Asia/Kolkata' -+ -+USE_I18N = True -+ -+USE_L10N = True -+ -+USE_TZ = True -+ -+ -+# Static files (CSS, JavaScript, Images) -+# https://docs.djangoproject.com/en/1.6/howto/static-files/ -+ -+STATIC_URL = '/static/' -diff --git a/infohub/settings.pyc b/infohub/settings.pyc -new file mode 100644 -index 0000000..4d2a608 -Binary files /dev/null and b/infohub/settings.pyc differ -diff --git a/infohub/urls.py b/infohub/urls.py -new file mode 100644 -index 0000000..8a0bde5 ---- /dev/null -+++ b/infohub/urls.py -@@ -0,0 +1,16 @@ -+from django.conf.urls import patterns, include, url -+ -+from django.contrib import admin -+admin.autodiscover() -+ -+urlpatterns = patterns('', -+ # Examples: -+ # url(r'^$', 'infohub.views.home', name='home'), -+ # url(r'^blog/', include('blog.urls')), -+ -+ url(r'^admin/', include(admin.site.urls)), -+ url(r'^', include('webhub.urls')), -+ -+ -+ -+) -diff --git a/infohub/urls.pyc b/infohub/urls.pyc -new file mode 100644 -index 0000000..41b429f -Binary files /dev/null and b/infohub/urls.pyc differ -diff --git a/infohub/wsgi.py b/infohub/wsgi.py -new file mode 100644 -index 0000000..8d0bb50 ---- /dev/null -+++ b/infohub/wsgi.py -@@ -0,0 +1,14 @@ -+""" -+WSGI config for infohub project. -+ -+It exposes the WSGI callable as a module-level variable named ``application``. -+ -+For more information on this file, see -+https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/ -+""" -+ -+import os -+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "infohub.settings") -+ -+from django.core.wsgi import get_wsgi_application -+application = get_wsgi_application() -diff --git a/infohub/wsgi.pyc b/infohub/wsgi.pyc -new file mode 100644 -index 0000000..af5136b -Binary files /dev/null and b/infohub/wsgi.pyc differ -diff --git a/manage.py b/manage.py -new file mode 100644 -index 0000000..c44b755 ---- /dev/null -+++ b/manage.py -@@ -0,0 +1,18 @@ -+#Version : Phython/Django 2.7.6, PostgreSQL 9.3.4 -+#Author : Vaibhavi Desai -+#Github username : desaivaibhavi -+#email : ranihaileydesai@gmail.com -+ -+#!/usr/bin/env python -+import os -+import sys -+ -+if __name__ == "__main__": -+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "infohub.settings") -+ -+ from django.core.management import execute_from_command_line -+ -+ execute_from_command_line(sys.argv) -+ -+ -+ -diff --git a/ui/bootstrap/css/bootstrap-theme.css b/ui/bootstrap/css/bootstrap-theme.css -new file mode 100644 -index 0000000..a406992 ---- /dev/null -+++ b/ui/bootstrap/css/bootstrap-theme.css -@@ -0,0 +1,347 @@ -+/*! -+ * Bootstrap v3.1.1 (http://getbootstrap.com) -+ * Copyright 2011-2014 Twitter, Inc. -+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) -+ */ -+ -+.btn-default, -+.btn-primary, -+.btn-success, -+.btn-info, -+.btn-warning, -+.btn-danger { -+ text-shadow: 0 -1px 0 rgba(0, 0, 0, .2); -+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); -+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); -+} -+.btn-default:active, -+.btn-primary:active, -+.btn-success:active, -+.btn-info:active, -+.btn-warning:active, -+.btn-danger:active, -+.btn-default.active, -+.btn-primary.active, -+.btn-success.active, -+.btn-info.active, -+.btn-warning.active, -+.btn-danger.active { -+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); -+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); -+} -+.btn:active, -+.btn.active { -+ background-image: none; -+} -+.btn-default { -+ text-shadow: 0 1px 0 #fff; -+ background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%); -+ background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); -+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); -+ background-repeat: repeat-x; -+ border-color: #dbdbdb; -+ border-color: #ccc; -+} -+.btn-default:hover, -+.btn-default:focus { -+ background-color: #e0e0e0; -+ background-position: 0 -15px; -+} -+.btn-default:active, -+.btn-default.active { -+ background-color: #e0e0e0; -+ border-color: #dbdbdb; -+} -+.btn-primary { -+ background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%); -+ background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0); -+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); -+ background-repeat: repeat-x; -+ border-color: #2b669a; -+} -+.btn-primary:hover, -+.btn-primary:focus { -+ background-color: #2d6ca2; -+ background-position: 0 -15px; -+} -+.btn-primary:active, -+.btn-primary.active { -+ background-color: #2d6ca2; -+ border-color: #2b669a; -+} -+.btn-success { -+ background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); -+ background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); -+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); -+ background-repeat: repeat-x; -+ border-color: #3e8f3e; -+} -+.btn-success:hover, -+.btn-success:focus { -+ background-color: #419641; -+ background-position: 0 -15px; -+} -+.btn-success:active, -+.btn-success.active { -+ background-color: #419641; -+ border-color: #3e8f3e; -+} -+.btn-info { -+ background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); -+ background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); -+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); -+ background-repeat: repeat-x; -+ border-color: #28a4c9; -+} -+.btn-info:hover, -+.btn-info:focus { -+ background-color: #2aabd2; -+ background-position: 0 -15px; -+} -+.btn-info:active, -+.btn-info.active { -+ background-color: #2aabd2; -+ border-color: #28a4c9; -+} -+.btn-warning { -+ background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); -+ background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); -+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); -+ background-repeat: repeat-x; -+ border-color: #e38d13; -+} -+.btn-warning:hover, -+.btn-warning:focus { -+ background-color: #eb9316; -+ background-position: 0 -15px; -+} -+.btn-warning:active, -+.btn-warning.active { -+ background-color: #eb9316; -+ border-color: #e38d13; -+} -+.btn-danger { -+ background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); -+ background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); -+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); -+ background-repeat: repeat-x; -+ border-color: #b92c28; -+} -+.btn-danger:hover, -+.btn-danger:focus { -+ background-color: #c12e2a; -+ background-position: 0 -15px; -+} -+.btn-danger:active, -+.btn-danger.active { -+ background-color: #c12e2a; -+ border-color: #b92c28; -+} -+.thumbnail, -+.img-thumbnail { -+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); -+ box-shadow: 0 1px 2px rgba(0, 0, 0, .075); -+} -+.dropdown-menu > li > a:hover, -+.dropdown-menu > li > a:focus { -+ background-color: #e8e8e8; -+ background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); -+ background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); -+ background-repeat: repeat-x; -+} -+.dropdown-menu > .active > a, -+.dropdown-menu > .active > a:hover, -+.dropdown-menu > .active > a:focus { -+ background-color: #357ebd; -+ background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); -+ background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); -+ background-repeat: repeat-x; -+} -+.navbar-default { -+ background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%); -+ background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); -+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); -+ background-repeat: repeat-x; -+ border-radius: 4px; -+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); -+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); -+} -+.navbar-default .navbar-nav > .active > a { -+ background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%); -+ background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0); -+ background-repeat: repeat-x; -+ -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); -+ box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); -+} -+.navbar-brand, -+.navbar-nav > li > a { -+ text-shadow: 0 1px 0 rgba(255, 255, 255, .25); -+} -+.navbar-inverse { -+ background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%); -+ background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); -+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); -+ background-repeat: repeat-x; -+} -+.navbar-inverse .navbar-nav > .active > a { -+ background-image: -webkit-linear-gradient(top, #222 0%, #282828 100%); -+ background-image: linear-gradient(to bottom, #222 0%, #282828 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0); -+ background-repeat: repeat-x; -+ -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); -+ box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); -+} -+.navbar-inverse .navbar-brand, -+.navbar-inverse .navbar-nav > li > a { -+ text-shadow: 0 -1px 0 rgba(0, 0, 0, .25); -+} -+.navbar-static-top, -+.navbar-fixed-top, -+.navbar-fixed-bottom { -+ border-radius: 0; -+} -+.alert { -+ text-shadow: 0 1px 0 rgba(255, 255, 255, .2); -+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); -+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); -+} -+.alert-success { -+ background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); -+ background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); -+ background-repeat: repeat-x; -+ border-color: #b2dba1; -+} -+.alert-info { -+ background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); -+ background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); -+ background-repeat: repeat-x; -+ border-color: #9acfea; -+} -+.alert-warning { -+ background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); -+ background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); -+ background-repeat: repeat-x; -+ border-color: #f5e79e; -+} -+.alert-danger { -+ background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); -+ background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); -+ background-repeat: repeat-x; -+ border-color: #dca7a7; -+} -+.progress { -+ background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); -+ background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); -+ background-repeat: repeat-x; -+} -+.progress-bar { -+ background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%); -+ background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0); -+ background-repeat: repeat-x; -+} -+.progress-bar-success { -+ background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); -+ background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); -+ background-repeat: repeat-x; -+} -+.progress-bar-info { -+ background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); -+ background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); -+ background-repeat: repeat-x; -+} -+.progress-bar-warning { -+ background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); -+ background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); -+ background-repeat: repeat-x; -+} -+.progress-bar-danger { -+ background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); -+ background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); -+ background-repeat: repeat-x; -+} -+.list-group { -+ border-radius: 4px; -+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); -+ box-shadow: 0 1px 2px rgba(0, 0, 0, .075); -+} -+.list-group-item.active, -+.list-group-item.active:hover, -+.list-group-item.active:focus { -+ text-shadow: 0 -1px 0 #3071a9; -+ background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%); -+ background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0); -+ background-repeat: repeat-x; -+ border-color: #3278b3; -+} -+.panel { -+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05); -+ box-shadow: 0 1px 2px rgba(0, 0, 0, .05); -+} -+.panel-default > .panel-heading { -+ background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); -+ background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); -+ background-repeat: repeat-x; -+} -+.panel-primary > .panel-heading { -+ background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); -+ background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); -+ background-repeat: repeat-x; -+} -+.panel-success > .panel-heading { -+ background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); -+ background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); -+ background-repeat: repeat-x; -+} -+.panel-info > .panel-heading { -+ background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); -+ background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); -+ background-repeat: repeat-x; -+} -+.panel-warning > .panel-heading { -+ background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); -+ background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); -+ background-repeat: repeat-x; -+} -+.panel-danger > .panel-heading { -+ background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); -+ background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); -+ background-repeat: repeat-x; -+} -+.well { -+ background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); -+ background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); -+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); -+ background-repeat: repeat-x; -+ border-color: #dcdcdc; -+ -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); -+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); -+} -+/*# sourceMappingURL=bootstrap-theme.css.map */ -diff --git a/ui/bootstrap/css/bootstrap-theme.css.map b/ui/bootstrap/css/bootstrap-theme.css.map -new file mode 100644 -index 0000000..b36fc9a ---- /dev/null -+++ b/ui/bootstrap/css/bootstrap-theme.css.map -@@ -0,0 +1 @@ -+{"version":3,"sources":["less/theme.less","less/mixins.less"],"names":[],"mappings":"AAeA;AACA;AACA;AACA;AACA;AACA;EACE,wCAAA;ECoGA,2FAAA;EACQ,mFAAA;;ADhGR,YAAC;AAAD,YAAC;AAAD,YAAC;AAAD,SAAC;AAAD,YAAC;AAAD,WAAC;AACD,YAAC;AAAD,YAAC;AAAD,YAAC;AAAD,SAAC;AAAD,YAAC;AAAD,WAAC;EC8FD,wDAAA;EACQ,gDAAA;;ADnER,IAAC;AACD,IAAC;EACC,sBAAA;;AAKJ;EC4PI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;EAyB2C,yBAAA;EAA2B,kBAAA;;AAvBtE,YAAC;AACD,YAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,YAAC;AACD,YAAC;EACC,yBAAA;EACA,qBAAA;;AAeJ;EC2PI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;;AAEA,YAAC;AACD,YAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,YAAC;AACD,YAAC;EACC,yBAAA;EACA,qBAAA;;AAgBJ;EC0PI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;;AAEA,YAAC;AACD,YAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,YAAC;AACD,YAAC;EACC,yBAAA;EACA,qBAAA;;AAiBJ;ECyPI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;;AAEA,SAAC;AACD,SAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,SAAC;AACD,SAAC;EACC,yBAAA;EACA,qBAAA;;AAkBJ;ECwPI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;;AAEA,YAAC;AACD,YAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,YAAC;AACD,YAAC;EACC,yBAAA;EACA,qBAAA;;AAmBJ;ECuPI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;;AAEA,WAAC;AACD,WAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,WAAC;AACD,WAAC;EACC,yBAAA;EACA,qBAAA;;AA2BJ;AACA;EC6CE,kDAAA;EACQ,0CAAA;;ADpCV,cAAe,KAAK,IAAG;AACvB,cAAe,KAAK,IAAG;ECmOnB,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;EDpOF,yBAAA;;AAEF,cAAe,UAAU;AACzB,cAAe,UAAU,IAAG;AAC5B,cAAe,UAAU,IAAG;EC6NxB,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED9NF,yBAAA;;AAUF;ECiNI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;EAoCF,mEAAA;EDrPA,kBAAA;ECaA,2FAAA;EACQ,mFAAA;;ADjBV,eAOE,YAAY,UAAU;EC0MpB,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;EApMF,wDAAA;EACQ,gDAAA;;ADLV;AACA,WAAY,KAAK;EACf,8CAAA;;AAIF;EC+LI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;EAoCF,mEAAA;;ADtOF,eAIE,YAAY,UAAU;EC2LpB,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;EApMF,uDAAA;EACQ,+CAAA;;ADCV,eASE;AATF,eAUE,YAAY,KAAK;EACf,yCAAA;;AAKJ;AACA;AACA;EACE,gBAAA;;AAUF;EACE,6CAAA;EChCA,0FAAA;EACQ,kFAAA;;AD2CV;ECqJI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED5JF,qBAAA;;AAKF;ECoJI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED5JF,qBAAA;;AAMF;ECmJI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED5JF,qBAAA;;AAOF;ECkJI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED5JF,qBAAA;;AAgBF;ECyII,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADlIJ;EC+HI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADjIJ;EC8HI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADhIJ;EC6HI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;AD/HJ;EC4HI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;AD9HJ;EC2HI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADtHJ;EACE,kBAAA;EC/EA,kDAAA;EACQ,0CAAA;;ADiFV,gBAAgB;AAChB,gBAAgB,OAAO;AACvB,gBAAgB,OAAO;EACrB,6BAAA;EC4GE,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED7GF,qBAAA;;AAUF;ECjGE,iDAAA;EACQ,yCAAA;;AD0GV,cAAe;ECsFX,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADxFJ,cAAe;ECqFX,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADvFJ,cAAe;ECoFX,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADtFJ,WAAY;ECmFR,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADrFJ,cAAe;ECkFX,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADpFJ,aAAc;ECiFV,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;AD5EJ;ECyEI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED1EF,qBAAA;EC1HA,yFAAA;EACQ,iFAAA","sourcesContent":["\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n // Reset the shadow\n &:active,\n &.active {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners\n background-repeat: repeat-x;\n border-color: darken(@btn-color, 14%);\n\n &:hover,\n &:focus {\n background-color: darken(@btn-color, 12%);\n background-position: 0 -15px;\n }\n\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n border-color: darken(@btn-color, 14%);\n }\n}\n\n// Common styles\n.btn {\n // Remove the gradient for the pressed/active state\n &:active,\n &.active {\n background-image: none;\n }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger { .btn-styles(@btn-danger-bg); }\n\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n border-radius: @navbar-border-radius;\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: darken(@navbar-default-bg, 5%); @end-color: darken(@navbar-default-bg, 2%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: @navbar-inverse-bg; @end-color: lighten(@navbar-inverse-bg, 2.5%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n }\n\n .navbar-brand,\n .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n text-shadow: 0 1px 0 rgba(255,255,255,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success { .alert-styles(@alert-success-bg); }\n.alert-info { .alert-styles(@alert-info-bg); }\n.alert-warning { .alert-styles(@alert-warning-bg); }\n.alert-danger { .alert-styles(@alert-danger-bg); }\n\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }\n\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n border-radius: @border-radius-base;\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n border-color: darken(@list-group-active-border, 7.5%);\n}\n\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n border-color: darken(@well-bg, 10%);\n @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n}\n","//\n// Mixins\n// --------------------------------------------------\n\n\n// Utilities\n// -------------------------\n\n// Clearfix\n// Source: http://nicolasgallagher.com/micro-clearfix-hack/\n//\n// For modern browsers\n// 1. The space content is one way to avoid an Opera bug when the\n// contenteditable attribute is included anywhere else in the document.\n// Otherwise it causes space to appear at the top and bottom of elements\n// that are clearfixed.\n// 2. The use of `table` rather than `block` is only necessary if using\n// `:before` to contain the top-margins of child elements.\n.clearfix() {\n &:before,\n &:after {\n content: \" \"; // 1\n display: table; // 2\n }\n &:after {\n clear: both;\n }\n}\n\n// WebKit-style focus\n.tab-focus() {\n // Default\n outline: thin dotted;\n // WebKit\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n\n// Center-align a block level element\n.center-block() {\n display: block;\n margin-left: auto;\n margin-right: auto;\n}\n\n// Sizing shortcuts\n.size(@width; @height) {\n width: @width;\n height: @height;\n}\n.square(@size) {\n .size(@size; @size);\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n &::-moz-placeholder { color: @color; // Firefox\n opacity: 1; } // See https://github.com/twbs/bootstrap/pull/11526\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Text overflow\n// Requires inline-block or block for proper styling\n.text-overflow() {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n// CSS image replacement\n//\n// Heads up! v3 launched with with only `.hide-text()`, but per our pattern for\n// mixins being reused as classes with the same name, this doesn't hold up. As\n// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`. Note\n// that we cannot chain the mixins together in Less, so they are repeated.\n//\n// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757\n\n// Deprecated as of v3.0.1 (will be removed in v4)\n.hide-text() {\n font: ~\"0/0\" a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n// New mixin to use as of v3.0.1\n.text-hide() {\n .hide-text();\n}\n\n\n\n// CSS3 PROPERTIES\n// --------------------------------------------------\n\n// Single side border-radius\n.border-top-radius(@radius) {\n border-top-right-radius: @radius;\n border-top-left-radius: @radius;\n}\n.border-right-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-top-right-radius: @radius;\n}\n.border-bottom-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-bottom-left-radius: @radius;\n}\n.border-left-radius(@radius) {\n border-bottom-left-radius: @radius;\n border-top-left-radius: @radius;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support the\n// standard `box-shadow` property.\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Transitions\n.transition(@transition) {\n -webkit-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n// Transformations\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n transform: rotate(@degrees);\n}\n.scale(@ratio; @ratio-y...) {\n -webkit-transform: scale(@ratio, @ratio-y);\n -ms-transform: scale(@ratio, @ratio-y); // IE9 only\n transform: scale(@ratio, @ratio-y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n transform: translate(@x, @y);\n}\n.skew(@x; @y) {\n -webkit-transform: skew(@x, @y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n transform: skew(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n.backface-visibility(@visibility){\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// User select\n// For selecting text on the page\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n\n// Resize anything\n.resizable(@direction) {\n resize: @direction; // Options: horizontal, vertical, both\n overflow: auto; // Safari fix\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Opacity\n.opacity(@opacity) {\n opacity: @opacity;\n // IE8 filter\n @opacity-ie: (@opacity * 100);\n filter: ~\"alpha(opacity=@{opacity-ie})\";\n}\n\n\n\n// GRADIENTS\n// --------------------------------------------------\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, color-stop(@start-color @start-percent), color-stop(@end-color @end-percent)); // Safari 5.1-6, Chrome 10+\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n\n// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n\n\n\n// Retina images\n//\n// Short retina mixin for setting background-image and -size\n\n.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {\n background-image: url(\"@{file-1x}\");\n\n @media\n only screen and (-webkit-min-device-pixel-ratio: 2),\n only screen and ( min--moz-device-pixel-ratio: 2),\n only screen and ( -o-min-device-pixel-ratio: 2/1),\n only screen and ( min-device-pixel-ratio: 2),\n only screen and ( min-resolution: 192dpi),\n only screen and ( min-resolution: 2dppx) {\n background-image: url(\"@{file-2x}\");\n background-size: @width-1x @height-1x;\n }\n}\n\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n\n.img-responsive(@display: block) {\n display: @display;\n max-width: 100%; // Part 1: Set a maximum relative to the parent\n height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching\n}\n\n\n// COMPONENT MIXINS\n// --------------------------------------------------\n\n// Horizontal dividers\n// -------------------------\n// Dividers (basically an hr) within dropdowns and nav lists\n.nav-divider(@color: #e5e5e5) {\n height: 1px;\n margin: ((@line-height-computed / 2) - 1) 0;\n overflow: hidden;\n background-color: @color;\n}\n\n// Panels\n// -------------------------\n.panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) {\n border-color: @border;\n\n & > .panel-heading {\n color: @heading-text-color;\n background-color: @heading-bg-color;\n border-color: @heading-border;\n\n + .panel-collapse .panel-body {\n border-top-color: @border;\n }\n }\n & > .panel-footer {\n + .panel-collapse .panel-body {\n border-bottom-color: @border;\n }\n }\n}\n\n// Alerts\n// -------------------------\n.alert-variant(@background; @border; @text-color) {\n background-color: @background;\n border-color: @border;\n color: @text-color;\n\n hr {\n border-top-color: darken(@border, 5%);\n }\n .alert-link {\n color: darken(@text-color, 10%);\n }\n}\n\n// Tables\n// -------------------------\n.table-row-variant(@state; @background) {\n // Exact selectors below required to override `.table-striped` and prevent\n // inheritance to nested tables.\n .table > thead > tr,\n .table > tbody > tr,\n .table > tfoot > tr {\n > td.@{state},\n > th.@{state},\n &.@{state} > td,\n &.@{state} > th {\n background-color: @background;\n }\n }\n\n // Hover states for `.table-hover`\n // Note: this is not available for cells or rows within `thead` or `tfoot`.\n .table-hover > tbody > tr {\n > td.@{state}:hover,\n > th.@{state}:hover,\n &.@{state}:hover > td,\n &.@{state}:hover > th {\n background-color: darken(@background, 5%);\n }\n }\n}\n\n// List Groups\n// -------------------------\n.list-group-item-variant(@state; @background; @color) {\n .list-group-item-@{state} {\n color: @color;\n background-color: @background;\n\n a& {\n color: @color;\n\n .list-group-item-heading { color: inherit; }\n\n &:hover,\n &:focus {\n color: @color;\n background-color: darken(@background, 5%);\n }\n &.active,\n &.active:hover,\n &.active:focus {\n color: #fff;\n background-color: @color;\n border-color: @color;\n }\n }\n }\n}\n\n// Button variants\n// -------------------------\n// Easily pump out default styles, as well as :hover, :focus, :active,\n// and disabled options for all buttons\n.button-variant(@color; @background; @border) {\n color: @color;\n background-color: @background;\n border-color: @border;\n\n &:hover,\n &:focus,\n &:active,\n &.active,\n .open .dropdown-toggle& {\n color: @color;\n background-color: darken(@background, 8%);\n border-color: darken(@border, 12%);\n }\n &:active,\n &.active,\n .open .dropdown-toggle& {\n background-image: none;\n }\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &,\n &:hover,\n &:focus,\n &:active,\n &.active {\n background-color: @background;\n border-color: @border;\n }\n }\n\n .badge {\n color: @background;\n background-color: @color;\n }\n}\n\n// Button sizes\n// -------------------------\n.button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n}\n\n// Pagination\n// -------------------------\n.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @border-radius) {\n > li {\n > a,\n > span {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n }\n &:first-child {\n > a,\n > span {\n .border-left-radius(@border-radius);\n }\n }\n &:last-child {\n > a,\n > span {\n .border-right-radius(@border-radius);\n }\n }\n }\n}\n\n// Labels\n// -------------------------\n.label-variant(@color) {\n background-color: @color;\n &[href] {\n &:hover,\n &:focus {\n background-color: darken(@color, 10%);\n }\n }\n}\n\n// Contextual backgrounds\n// -------------------------\n.bg-variant(@color) {\n background-color: @color;\n a&:hover {\n background-color: darken(@color, 10%);\n }\n}\n\n// Typography\n// -------------------------\n.text-emphasis-variant(@color) {\n color: @color;\n a&:hover {\n color: darken(@color, 10%);\n }\n}\n\n// Navbar vertical align\n// -------------------------\n// Vertically center elements in the navbar.\n// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.\n.navbar-vertical-align(@element-height) {\n margin-top: ((@navbar-height - @element-height) / 2);\n margin-bottom: ((@navbar-height - @element-height) / 2);\n}\n\n// Progress bars\n// -------------------------\n.progress-bar-variant(@color) {\n background-color: @color;\n .progress-striped & {\n #gradient > .striped();\n }\n}\n\n// Responsive utilities\n// -------------------------\n// More easily include all the states for responsive-utilities.less.\n.responsive-visibility() {\n display: block !important;\n table& { display: table; }\n tr& { display: table-row !important; }\n th&,\n td& { display: table-cell !important; }\n}\n\n.responsive-invisibility() {\n display: none !important;\n}\n\n\n// Grid System\n// -----------\n\n// Centered container element\n.container-fixed() {\n margin-right: auto;\n margin-left: auto;\n padding-left: (@grid-gutter-width / 2);\n padding-right: (@grid-gutter-width / 2);\n &:extend(.clearfix all);\n}\n\n// Creates a wrapper for a series of columns\n.make-row(@gutter: @grid-gutter-width) {\n margin-left: (@gutter / -2);\n margin-right: (@gutter / -2);\n &:extend(.clearfix all);\n}\n\n// Generate the extra small columns\n.make-xs-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n float: left;\n width: percentage((@columns / @grid-columns));\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n}\n.make-xs-column-offset(@columns) {\n @media (min-width: @screen-xs-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-xs-column-push(@columns) {\n @media (min-width: @screen-xs-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-xs-column-pull(@columns) {\n @media (min-width: @screen-xs-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Generate the small columns\n.make-sm-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-sm-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-offset(@columns) {\n @media (min-width: @screen-sm-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-push(@columns) {\n @media (min-width: @screen-sm-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-pull(@columns) {\n @media (min-width: @screen-sm-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Generate the medium columns\n.make-md-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-md-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-offset(@columns) {\n @media (min-width: @screen-md-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-push(@columns) {\n @media (min-width: @screen-md-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-pull(@columns) {\n @media (min-width: @screen-md-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Generate the large columns\n.make-lg-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-lg-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-offset(@columns) {\n @media (min-width: @screen-lg-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-push(@columns) {\n @media (min-width: @screen-lg-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-pull(@columns) {\n @media (min-width: @screen-lg-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `@grid-columns`.\n\n.make-grid-columns() {\n // Common styles for all sizes of grid columns, widths 1-12\n .col(@index) when (@index = 1) { // initial\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general; \"=<\" isn't a typo\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n position: relative;\n // Prevent columns from collapsing when empty\n min-height: 1px;\n // Inner gutter via padding\n padding-left: (@grid-gutter-width / 2);\n padding-right: (@grid-gutter-width / 2);\n }\n }\n .col(1); // kickstart it\n}\n\n.float-grid-columns(@class) {\n .col(@index) when (@index = 1) { // initial\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n float: left;\n }\n }\n .col(1); // kickstart it\n}\n\n.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {\n .col-@{class}-@{index} {\n width: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) {\n .col-@{class}-push-@{index} {\n left: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) {\n .col-@{class}-pull-@{index} {\n right: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = offset) {\n .col-@{class}-offset-@{index} {\n margin-left: percentage((@index / @grid-columns));\n }\n}\n\n// Basic looping in LESS\n.loop-grid-columns(@index, @class, @type) when (@index >= 0) {\n .calc-grid-column(@index, @class, @type);\n // next iteration\n .loop-grid-columns((@index - 1), @class, @type);\n}\n\n// Create grid for specific class\n.make-grid(@class) {\n .float-grid-columns(@class);\n .loop-grid-columns(@grid-columns, @class, width);\n .loop-grid-columns(@grid-columns, @class, pull);\n .loop-grid-columns(@grid-columns, @class, push);\n .loop-grid-columns(@grid-columns, @class, offset);\n}\n\n// Form validation states\n//\n// Used in forms.less to generate the form validation CSS for warnings, errors,\n// and successes.\n\n.form-control-validation(@text-color: #555; @border-color: #ccc; @background-color: #f5f5f5) {\n // Color the label and help text\n .help-block,\n .control-label,\n .radio,\n .checkbox,\n .radio-inline,\n .checkbox-inline {\n color: @text-color;\n }\n // Set the border and box shadow on specific inputs to match\n .form-control {\n border-color: @border-color;\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work\n &:focus {\n border-color: darken(@border-color, 10%);\n @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@border-color, 20%);\n .box-shadow(@shadow);\n }\n }\n // Set validation states also for addons\n .input-group-addon {\n color: @text-color;\n border-color: @border-color;\n background-color: @background-color;\n }\n // Optional feedback icon\n .form-control-feedback {\n color: @text-color;\n }\n}\n\n// Form control focus state\n//\n// Generate a customized focus state and for any input with the specified color,\n// which defaults to the `@input-focus-border` variable.\n//\n// We highly encourage you to not customize the default value, but instead use\n// this to tweak colors on an as-needed basis. This aesthetic change is based on\n// WebKit's default styles, but applicable to a wider range of browsers. Its\n// usability and accessibility should be taken into account with any change.\n//\n// Example usage: change the default blue border and shadow to white for better\n// contrast against a dark gray background.\n\n.form-control-focus(@color: @input-border-focus) {\n @color-rgba: rgba(red(@color), green(@color), blue(@color), .6);\n &:focus {\n border-color: @color;\n outline: 0;\n .box-shadow(~\"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px @{color-rgba}\");\n }\n}\n\n// Form control sizing\n//\n// Relative text size, padding, and border-radii changes for form controls. For\n// horizontal sizing, wrap controls in the predefined grid classes. ``\n// element gets special love because it's special, and that's a fact!\n\n.input-size(@input-height; @padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n height: @input-height;\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n\n select& {\n height: @input-height;\n line-height: @input-height;\n }\n\n textarea&,\n select[multiple]& {\n height: auto;\n }\n}\n","//\n// Variables\n// --------------------------------------------------\n\n\n//== Colors\n//\n//## Gray and brand colors for use across Bootstrap.\n\n@gray-darker: lighten(#000, 13.5%); // #222\n@gray-dark: lighten(#000, 20%); // #333\n@gray: lighten(#000, 33.5%); // #555\n@gray-light: lighten(#000, 60%); // #999\n@gray-lighter: lighten(#000, 93.5%); // #eee\n\n@brand-primary: #428bca;\n@brand-success: #5cb85c;\n@brand-info: #5bc0de;\n@brand-warning: #f0ad4e;\n@brand-danger: #d9534f;\n\n\n//== Scaffolding\n//\n// ## Settings for some of the most global styles.\n\n//** Background color for ``.\n@body-bg: #fff;\n//** Global text color on ``.\n@text-color: @gray-dark;\n\n//** Global textual link color.\n@link-color: @brand-primary;\n//** Link hover color set via `darken()` function.\n@link-hover-color: darken(@link-color, 15%);\n\n\n//== Typography\n//\n//## Font, line-height, and color for body text, headings, and more.\n\n@font-family-sans-serif: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n@font-family-serif: Georgia, \"Times New Roman\", Times, serif;\n//** Default monospace fonts for ``, ``, and `
    `.\n@font-family-monospace:   Menlo, Monaco, Consolas, \"Courier New\", monospace;\n@font-family-base:        @font-family-sans-serif;\n\n@font-size-base:          14px;\n@font-size-large:         ceil((@font-size-base * 1.25)); // ~18px\n@font-size-small:         ceil((@font-size-base * 0.85)); // ~12px\n\n@font-size-h1:            floor((@font-size-base * 2.6)); // ~36px\n@font-size-h2:            floor((@font-size-base * 2.15)); // ~30px\n@font-size-h3:            ceil((@font-size-base * 1.7)); // ~24px\n@font-size-h4:            ceil((@font-size-base * 1.25)); // ~18px\n@font-size-h5:            @font-size-base;\n@font-size-h6:            ceil((@font-size-base * 0.85)); // ~12px\n\n//** Unit-less `line-height` for use in components like buttons.\n@line-height-base:        1.428571429; // 20/14\n//** Computed \"line-height\" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.\n@line-height-computed:    floor((@font-size-base * @line-height-base)); // ~20px\n\n//** By default, this inherits from the ``.\n@headings-font-family:    inherit;\n@headings-font-weight:    500;\n@headings-line-height:    1.1;\n@headings-color:          inherit;\n\n\n//-- Iconography\n//\n//## Specify custom locations of the include Glyphicons icon font. Useful for those including Bootstrap via Bower.\n\n@icon-font-path:          \"../fonts/\";\n@icon-font-name:          \"glyphicons-halflings-regular\";\n@icon-font-svg-id:        \"glyphicons_halflingsregular\";\n\n//== Components\n//\n//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).\n\n@padding-base-vertical:     6px;\n@padding-base-horizontal:   12px;\n\n@padding-large-vertical:    10px;\n@padding-large-horizontal:  16px;\n\n@padding-small-vertical:    5px;\n@padding-small-horizontal:  10px;\n\n@padding-xs-vertical:       1px;\n@padding-xs-horizontal:     5px;\n\n@line-height-large:         1.33;\n@line-height-small:         1.5;\n\n@border-radius-base:        4px;\n@border-radius-large:       6px;\n@border-radius-small:       3px;\n\n//** Global color for active items (e.g., navs or dropdowns).\n@component-active-color:    #fff;\n//** Global background color for active items (e.g., navs or dropdowns).\n@component-active-bg:       @brand-primary;\n\n//** Width of the `border` for generating carets that indicator dropdowns.\n@caret-width-base:          4px;\n//** Carets increase slightly in size for larger components.\n@caret-width-large:         5px;\n\n\n//== Tables\n//\n//## Customizes the `.table` component with basic values, each used across all table variations.\n\n//** Padding for ``s and ``s.\n@table-cell-padding:            8px;\n//** Padding for cells in `.table-condensed`.\n@table-condensed-cell-padding:  5px;\n\n//** Default background color used for all tables.\n@table-bg:                      transparent;\n//** Background color used for `.table-striped`.\n@table-bg-accent:               #f9f9f9;\n//** Background color used for `.table-hover`.\n@table-bg-hover:                #f5f5f5;\n@table-bg-active:               @table-bg-hover;\n\n//** Border color for table and cell borders.\n@table-border-color:            #ddd;\n\n\n//== Buttons\n//\n//## For each of Bootstrap's buttons, define text, background and border color.\n\n@btn-font-weight:                normal;\n\n@btn-default-color:              #333;\n@btn-default-bg:                 #fff;\n@btn-default-border:             #ccc;\n\n@btn-primary-color:              #fff;\n@btn-primary-bg:                 @brand-primary;\n@btn-primary-border:             darken(@btn-primary-bg, 5%);\n\n@btn-success-color:              #fff;\n@btn-success-bg:                 @brand-success;\n@btn-success-border:             darken(@btn-success-bg, 5%);\n\n@btn-info-color:                 #fff;\n@btn-info-bg:                    @brand-info;\n@btn-info-border:                darken(@btn-info-bg, 5%);\n\n@btn-warning-color:              #fff;\n@btn-warning-bg:                 @brand-warning;\n@btn-warning-border:             darken(@btn-warning-bg, 5%);\n\n@btn-danger-color:               #fff;\n@btn-danger-bg:                  @brand-danger;\n@btn-danger-border:              darken(@btn-danger-bg, 5%);\n\n@btn-link-disabled-color:        @gray-light;\n\n\n//== Forms\n//\n//##\n\n//** `` background color\n@input-bg:                       #fff;\n//** `` background color\n@input-bg-disabled:              @gray-lighter;\n\n//** Text color for ``s\n@input-color:                    @gray;\n//** `` border color\n@input-border:                   #ccc;\n//** `` border radius\n@input-border-radius:            @border-radius-base;\n//** Border color for inputs on focus\n@input-border-focus:             #66afe9;\n\n//** Placeholder text color\n@input-color-placeholder:        @gray-light;\n\n//** Default `.form-control` height\n@input-height-base:              (@line-height-computed + (@padding-base-vertical * 2) + 2);\n//** Large `.form-control` height\n@input-height-large:             (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);\n//** Small `.form-control` height\n@input-height-small:             (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2);\n\n@legend-color:                   @gray-dark;\n@legend-border-color:            #e5e5e5;\n\n//** Background color for textual input addons\n@input-group-addon-bg:           @gray-lighter;\n//** Border color for textual input addons\n@input-group-addon-border-color: @input-border;\n\n\n//== Dropdowns\n//\n//## Dropdown menu container and contents.\n\n//** Background for the dropdown menu.\n@dropdown-bg:                    #fff;\n//** Dropdown menu `border-color`.\n@dropdown-border:                rgba(0,0,0,.15);\n//** Dropdown menu `border-color` **for IE8**.\n@dropdown-fallback-border:       #ccc;\n//** Divider color for between dropdown items.\n@dropdown-divider-bg:            #e5e5e5;\n\n//** Dropdown link text color.\n@dropdown-link-color:            @gray-dark;\n//** Hover color for dropdown links.\n@dropdown-link-hover-color:      darken(@gray-dark, 5%);\n//** Hover background for dropdown links.\n@dropdown-link-hover-bg:         #f5f5f5;\n\n//** Active dropdown menu item text color.\n@dropdown-link-active-color:     @component-active-color;\n//** Active dropdown menu item background color.\n@dropdown-link-active-bg:        @component-active-bg;\n\n//** Disabled dropdown menu item background color.\n@dropdown-link-disabled-color:   @gray-light;\n\n//** Text color for headers within dropdown menus.\n@dropdown-header-color:          @gray-light;\n\n// Note: Deprecated @dropdown-caret-color as of v3.1.0\n@dropdown-caret-color:           #000;\n\n\n//-- Z-index master list\n//\n// Warning: Avoid customizing these values. They're used for a bird's eye view\n// of components dependent on the z-axis and are designed to all work together.\n//\n// Note: These variables are not generated into the Customizer.\n\n@zindex-navbar:            1000;\n@zindex-dropdown:          1000;\n@zindex-popover:           1010;\n@zindex-tooltip:           1030;\n@zindex-navbar-fixed:      1030;\n@zindex-modal-background:  1040;\n@zindex-modal:             1050;\n\n\n//== Media queries breakpoints\n//\n//## Define the breakpoints at which your layout will change, adapting to different screen sizes.\n\n// Extra small screen / phone\n// Note: Deprecated @screen-xs and @screen-phone as of v3.0.1\n@screen-xs:                  480px;\n@screen-xs-min:              @screen-xs;\n@screen-phone:               @screen-xs-min;\n\n// Small screen / tablet\n// Note: Deprecated @screen-sm and @screen-tablet as of v3.0.1\n@screen-sm:                  768px;\n@screen-sm-min:              @screen-sm;\n@screen-tablet:              @screen-sm-min;\n\n// Medium screen / desktop\n// Note: Deprecated @screen-md and @screen-desktop as of v3.0.1\n@screen-md:                  992px;\n@screen-md-min:              @screen-md;\n@screen-desktop:             @screen-md-min;\n\n// Large screen / wide desktop\n// Note: Deprecated @screen-lg and @screen-lg-desktop as of v3.0.1\n@screen-lg:                  1200px;\n@screen-lg-min:              @screen-lg;\n@screen-lg-desktop:          @screen-lg-min;\n\n// So media queries don't overlap when required, provide a maximum\n@screen-xs-max:              (@screen-sm-min - 1);\n@screen-sm-max:              (@screen-md-min - 1);\n@screen-md-max:              (@screen-lg-min - 1);\n\n\n//== Grid system\n//\n//## Define your custom responsive grid.\n\n//** Number of columns in the grid.\n@grid-columns:              12;\n//** Padding between columns. Gets divided in half for the left and right.\n@grid-gutter-width:         30px;\n// Navbar collapse\n//** Point at which the navbar becomes uncollapsed.\n@grid-float-breakpoint:     @screen-sm-min;\n//** Point at which the navbar begins collapsing.\n@grid-float-breakpoint-max: (@grid-float-breakpoint - 1);\n\n\n//== Container sizes\n//\n//## Define the maximum width of `.container` for different screen sizes.\n\n// Small screen / tablet\n@container-tablet:             ((720px + @grid-gutter-width));\n//** For `@screen-sm-min` and up.\n@container-sm:                 @container-tablet;\n\n// Medium screen / desktop\n@container-desktop:            ((940px + @grid-gutter-width));\n//** For `@screen-md-min` and up.\n@container-md:                 @container-desktop;\n\n// Large screen / wide desktop\n@container-large-desktop:      ((1140px + @grid-gutter-width));\n//** For `@screen-lg-min` and up.\n@container-lg:                 @container-large-desktop;\n\n\n//== Navbar\n//\n//##\n\n// Basics of a navbar\n@navbar-height:                    50px;\n@navbar-margin-bottom:             @line-height-computed;\n@navbar-border-radius:             @border-radius-base;\n@navbar-padding-horizontal:        floor((@grid-gutter-width / 2));\n@navbar-padding-vertical:          ((@navbar-height - @line-height-computed) / 2);\n@navbar-collapse-max-height:       340px;\n\n@navbar-default-color:             #777;\n@navbar-default-bg:                #f8f8f8;\n@navbar-default-border:            darken(@navbar-default-bg, 6.5%);\n\n// Navbar links\n@navbar-default-link-color:                #777;\n@navbar-default-link-hover-color:          #333;\n@navbar-default-link-hover-bg:             transparent;\n@navbar-default-link-active-color:         #555;\n@navbar-default-link-active-bg:            darken(@navbar-default-bg, 6.5%);\n@navbar-default-link-disabled-color:       #ccc;\n@navbar-default-link-disabled-bg:          transparent;\n\n// Navbar brand label\n@navbar-default-brand-color:               @navbar-default-link-color;\n@navbar-default-brand-hover-color:         darken(@navbar-default-brand-color, 10%);\n@navbar-default-brand-hover-bg:            transparent;\n\n// Navbar toggle\n@navbar-default-toggle-hover-bg:           #ddd;\n@navbar-default-toggle-icon-bar-bg:        #888;\n@navbar-default-toggle-border-color:       #ddd;\n\n\n// Inverted navbar\n// Reset inverted navbar basics\n@navbar-inverse-color:                      @gray-light;\n@navbar-inverse-bg:                         #222;\n@navbar-inverse-border:                     darken(@navbar-inverse-bg, 10%);\n\n// Inverted navbar links\n@navbar-inverse-link-color:                 @gray-light;\n@navbar-inverse-link-hover-color:           #fff;\n@navbar-inverse-link-hover-bg:              transparent;\n@navbar-inverse-link-active-color:          @navbar-inverse-link-hover-color;\n@navbar-inverse-link-active-bg:             darken(@navbar-inverse-bg, 10%);\n@navbar-inverse-link-disabled-color:        #444;\n@navbar-inverse-link-disabled-bg:           transparent;\n\n// Inverted navbar brand label\n@navbar-inverse-brand-color:                @navbar-inverse-link-color;\n@navbar-inverse-brand-hover-color:          #fff;\n@navbar-inverse-brand-hover-bg:             transparent;\n\n// Inverted navbar toggle\n@navbar-inverse-toggle-hover-bg:            #333;\n@navbar-inverse-toggle-icon-bar-bg:         #fff;\n@navbar-inverse-toggle-border-color:        #333;\n\n\n//== Navs\n//\n//##\n\n//=== Shared nav styles\n@nav-link-padding:                          10px 15px;\n@nav-link-hover-bg:                         @gray-lighter;\n\n@nav-disabled-link-color:                   @gray-light;\n@nav-disabled-link-hover-color:             @gray-light;\n\n@nav-open-link-hover-color:                 #fff;\n\n//== Tabs\n@nav-tabs-border-color:                     #ddd;\n\n@nav-tabs-link-hover-border-color:          @gray-lighter;\n\n@nav-tabs-active-link-hover-bg:             @body-bg;\n@nav-tabs-active-link-hover-color:          @gray;\n@nav-tabs-active-link-hover-border-color:   #ddd;\n\n@nav-tabs-justified-link-border-color:            #ddd;\n@nav-tabs-justified-active-link-border-color:     @body-bg;\n\n//== Pills\n@nav-pills-border-radius:                   @border-radius-base;\n@nav-pills-active-link-hover-bg:            @component-active-bg;\n@nav-pills-active-link-hover-color:         @component-active-color;\n\n\n//== Pagination\n//\n//##\n\n@pagination-color:                     @link-color;\n@pagination-bg:                        #fff;\n@pagination-border:                    #ddd;\n\n@pagination-hover-color:               @link-hover-color;\n@pagination-hover-bg:                  @gray-lighter;\n@pagination-hover-border:              #ddd;\n\n@pagination-active-color:              #fff;\n@pagination-active-bg:                 @brand-primary;\n@pagination-active-border:             @brand-primary;\n\n@pagination-disabled-color:            @gray-light;\n@pagination-disabled-bg:               #fff;\n@pagination-disabled-border:           #ddd;\n\n\n//== Pager\n//\n//##\n\n@pager-bg:                             @pagination-bg;\n@pager-border:                         @pagination-border;\n@pager-border-radius:                  15px;\n\n@pager-hover-bg:                       @pagination-hover-bg;\n\n@pager-active-bg:                      @pagination-active-bg;\n@pager-active-color:                   @pagination-active-color;\n\n@pager-disabled-color:                 @pagination-disabled-color;\n\n\n//== Jumbotron\n//\n//##\n\n@jumbotron-padding:              30px;\n@jumbotron-color:                inherit;\n@jumbotron-bg:                   @gray-lighter;\n@jumbotron-heading-color:        inherit;\n@jumbotron-font-size:            ceil((@font-size-base * 1.5));\n\n\n//== Form states and alerts\n//\n//## Define colors for form feedback states and, by default, alerts.\n\n@state-success-text:             #3c763d;\n@state-success-bg:               #dff0d8;\n@state-success-border:           darken(spin(@state-success-bg, -10), 5%);\n\n@state-info-text:                #31708f;\n@state-info-bg:                  #d9edf7;\n@state-info-border:              darken(spin(@state-info-bg, -10), 7%);\n\n@state-warning-text:             #8a6d3b;\n@state-warning-bg:               #fcf8e3;\n@state-warning-border:           darken(spin(@state-warning-bg, -10), 5%);\n\n@state-danger-text:              #a94442;\n@state-danger-bg:                #f2dede;\n@state-danger-border:            darken(spin(@state-danger-bg, -10), 5%);\n\n\n//== Tooltips\n//\n//##\n\n//** Tooltip max width\n@tooltip-max-width:           200px;\n//** Tooltip text color\n@tooltip-color:               #fff;\n//** Tooltip background color\n@tooltip-bg:                  #000;\n@tooltip-opacity:             .9;\n\n//** Tooltip arrow width\n@tooltip-arrow-width:         5px;\n//** Tooltip arrow color\n@tooltip-arrow-color:         @tooltip-bg;\n\n\n//== Popovers\n//\n//##\n\n//** Popover body background color\n@popover-bg:                          #fff;\n//** Popover maximum width\n@popover-max-width:                   276px;\n//** Popover border color\n@popover-border-color:                rgba(0,0,0,.2);\n//** Popover fallback border color\n@popover-fallback-border-color:       #ccc;\n\n//** Popover title background color\n@popover-title-bg:                    darken(@popover-bg, 3%);\n\n//** Popover arrow width\n@popover-arrow-width:                 10px;\n//** Popover arrow color\n@popover-arrow-color:                 #fff;\n\n//** Popover outer arrow width\n@popover-arrow-outer-width:           (@popover-arrow-width + 1);\n//** Popover outer arrow color\n@popover-arrow-outer-color:           fadein(@popover-border-color, 5%);\n//** Popover outer arrow fallback color\n@popover-arrow-outer-fallback-color:  darken(@popover-fallback-border-color, 20%);\n\n\n//== Labels\n//\n//##\n\n//** Default label background color\n@label-default-bg:            @gray-light;\n//** Primary label background color\n@label-primary-bg:            @brand-primary;\n//** Success label background color\n@label-success-bg:            @brand-success;\n//** Info label background color\n@label-info-bg:               @brand-info;\n//** Warning label background color\n@label-warning-bg:            @brand-warning;\n//** Danger label background color\n@label-danger-bg:             @brand-danger;\n\n//** Default label text color\n@label-color:                 #fff;\n//** Default text color of a linked label\n@label-link-hover-color:      #fff;\n\n\n//== Modals\n//\n//##\n\n//** Padding applied to the modal body\n@modal-inner-padding:         20px;\n\n//** Padding applied to the modal title\n@modal-title-padding:         15px;\n//** Modal title line-height\n@modal-title-line-height:     @line-height-base;\n\n//** Background color of modal content area\n@modal-content-bg:                             #fff;\n//** Modal content border color\n@modal-content-border-color:                   rgba(0,0,0,.2);\n//** Modal content border color **for IE8**\n@modal-content-fallback-border-color:          #999;\n\n//** Modal backdrop background color\n@modal-backdrop-bg:           #000;\n//** Modal backdrop opacity\n@modal-backdrop-opacity:      .5;\n//** Modal header border color\n@modal-header-border-color:   #e5e5e5;\n//** Modal footer border color\n@modal-footer-border-color:   @modal-header-border-color;\n\n@modal-lg:                    900px;\n@modal-md:                    600px;\n@modal-sm:                    300px;\n\n\n//== Alerts\n//\n//## Define alert colors, border radius, and padding.\n\n@alert-padding:               15px;\n@alert-border-radius:         @border-radius-base;\n@alert-link-font-weight:      bold;\n\n@alert-success-bg:            @state-success-bg;\n@alert-success-text:          @state-success-text;\n@alert-success-border:        @state-success-border;\n\n@alert-info-bg:               @state-info-bg;\n@alert-info-text:             @state-info-text;\n@alert-info-border:           @state-info-border;\n\n@alert-warning-bg:            @state-warning-bg;\n@alert-warning-text:          @state-warning-text;\n@alert-warning-border:        @state-warning-border;\n\n@alert-danger-bg:             @state-danger-bg;\n@alert-danger-text:           @state-danger-text;\n@alert-danger-border:         @state-danger-border;\n\n\n//== Progress bars\n//\n//##\n\n//** Background color of the whole progress component\n@progress-bg:                 #f5f5f5;\n//** Progress bar text color\n@progress-bar-color:          #fff;\n\n//** Default progress bar color\n@progress-bar-bg:             @brand-primary;\n//** Success progress bar color\n@progress-bar-success-bg:     @brand-success;\n//** Warning progress bar color\n@progress-bar-warning-bg:     @brand-warning;\n//** Danger progress bar color\n@progress-bar-danger-bg:      @brand-danger;\n//** Info progress bar color\n@progress-bar-info-bg:        @brand-info;\n\n\n//== List group\n//\n//##\n\n//** Background color on `.list-group-item`\n@list-group-bg:                 #fff;\n//** `.list-group-item` border color\n@list-group-border:             #ddd;\n//** List group border radius\n@list-group-border-radius:      @border-radius-base;\n\n//** Background color of single list elements on hover\n@list-group-hover-bg:           #f5f5f5;\n//** Text color of active list elements\n@list-group-active-color:       @component-active-color;\n//** Background color of active list elements\n@list-group-active-bg:          @component-active-bg;\n//** Border color of active list elements\n@list-group-active-border:      @list-group-active-bg;\n@list-group-active-text-color:  lighten(@list-group-active-bg, 40%);\n\n@list-group-link-color:         #555;\n@list-group-link-heading-color: #333;\n\n\n//== Panels\n//\n//##\n\n@panel-bg:                    #fff;\n@panel-body-padding:          15px;\n@panel-border-radius:         @border-radius-base;\n\n//** Border color for elements within panels\n@panel-inner-border:          #ddd;\n@panel-footer-bg:             #f5f5f5;\n\n@panel-default-text:          @gray-dark;\n@panel-default-border:        #ddd;\n@panel-default-heading-bg:    #f5f5f5;\n\n@panel-primary-text:          #fff;\n@panel-primary-border:        @brand-primary;\n@panel-primary-heading-bg:    @brand-primary;\n\n@panel-success-text:          @state-success-text;\n@panel-success-border:        @state-success-border;\n@panel-success-heading-bg:    @state-success-bg;\n\n@panel-info-text:             @state-info-text;\n@panel-info-border:           @state-info-border;\n@panel-info-heading-bg:       @state-info-bg;\n\n@panel-warning-text:          @state-warning-text;\n@panel-warning-border:        @state-warning-border;\n@panel-warning-heading-bg:    @state-warning-bg;\n\n@panel-danger-text:           @state-danger-text;\n@panel-danger-border:         @state-danger-border;\n@panel-danger-heading-bg:     @state-danger-bg;\n\n\n//== Thumbnails\n//\n//##\n\n//** Padding around the thumbnail image\n@thumbnail-padding:           4px;\n//** Thumbnail background color\n@thumbnail-bg:                @body-bg;\n//** Thumbnail border color\n@thumbnail-border:            #ddd;\n//** Thumbnail border radius\n@thumbnail-border-radius:     @border-radius-base;\n\n//** Custom text color for thumbnail captions\n@thumbnail-caption-color:     @text-color;\n//** Padding around the thumbnail caption\n@thumbnail-caption-padding:   9px;\n\n\n//== Wells\n//\n//##\n\n@well-bg:                     #f5f5f5;\n@well-border:                 darken(@well-bg, 7%);\n\n\n//== Badges\n//\n//##\n\n@badge-color:                 #fff;\n//** Linked badge text color on hover\n@badge-link-hover-color:      #fff;\n@badge-bg:                    @gray-light;\n\n//** Badge text color in active nav link\n@badge-active-color:          @link-color;\n//** Badge background color in active nav link\n@badge-active-bg:             #fff;\n\n@badge-font-weight:           bold;\n@badge-line-height:           1;\n@badge-border-radius:         10px;\n\n\n//== Breadcrumbs\n//\n//##\n\n@breadcrumb-padding-vertical:   8px;\n@breadcrumb-padding-horizontal: 15px;\n//** Breadcrumb background color\n@breadcrumb-bg:                 #f5f5f5;\n//** Breadcrumb text color\n@breadcrumb-color:              #ccc;\n//** Text color of current page in the breadcrumb\n@breadcrumb-active-color:       @gray-light;\n//** Textual separator for between breadcrumb elements\n@breadcrumb-separator:          \"/\";\n\n\n//== Carousel\n//\n//##\n\n@carousel-text-shadow:                        0 1px 2px rgba(0,0,0,.6);\n\n@carousel-control-color:                      #fff;\n@carousel-control-width:                      15%;\n@carousel-control-opacity:                    .5;\n@carousel-control-font-size:                  20px;\n\n@carousel-indicator-active-bg:                #fff;\n@carousel-indicator-border-color:             #fff;\n\n@carousel-caption-color:                      #fff;\n\n\n//== Close\n//\n//##\n\n@close-font-weight:           bold;\n@close-color:                 #000;\n@close-text-shadow:           0 1px 0 #fff;\n\n\n//== Code\n//\n//##\n\n@code-color:                  #c7254e;\n@code-bg:                     #f9f2f4;\n\n@kbd-color:                   #fff;\n@kbd-bg:                      #333;\n\n@pre-bg:                      #f5f5f5;\n@pre-color:                   @gray-dark;\n@pre-border-color:            #ccc;\n@pre-scrollable-max-height:   340px;\n\n\n//== Type\n//\n//##\n\n//** Text muted color\n@text-muted:                  @gray-light;\n//** Abbreviations and acronyms border color\n@abbr-border-color:           @gray-light;\n//** Headings small color\n@headings-small-color:        @gray-light;\n//** Blockquote small color\n@blockquote-small-color:      @gray-light;\n//** Blockquote font size\n@blockquote-font-size:        (@font-size-base * 1.25);\n//** Blockquote border color\n@blockquote-border-color:     @gray-lighter;\n//** Page header border color\n@page-header-border-color:    @gray-lighter;\n\n\n//== Miscellaneous\n//\n//##\n\n//** Horizontal line color.\n@hr-border:                   @gray-lighter;\n\n//** Horizontal offset for forms and lists.\n@component-offset-horizontal: 180px;\n","//\n// Thumbnails\n// --------------------------------------------------\n\n\n// Mixin and adjust the regular image class\n.thumbnail {\n  display: block;\n  padding: @thumbnail-padding;\n  margin-bottom: @line-height-computed;\n  line-height: @line-height-base;\n  background-color: @thumbnail-bg;\n  border: 1px solid @thumbnail-border;\n  border-radius: @thumbnail-border-radius;\n  .transition(all .2s ease-in-out);\n\n  > img,\n  a > img {\n    &:extend(.img-responsive);\n    margin-left: auto;\n    margin-right: auto;\n  }\n\n  // Add a hover state for linked versions only\n  a&:hover,\n  a&:focus,\n  a&.active {\n    border-color: @link-color;\n  }\n\n  // Image captions\n  .caption {\n    padding: @thumbnail-caption-padding;\n    color: @thumbnail-caption-color;\n  }\n}\n","//\n// Carousel\n// --------------------------------------------------\n\n\n// Wrapper for the slide container and indicators\n.carousel {\n  position: relative;\n}\n\n.carousel-inner {\n  position: relative;\n  overflow: hidden;\n  width: 100%;\n\n  > .item {\n    display: none;\n    position: relative;\n    .transition(.6s ease-in-out left);\n\n    // Account for jankitude on images\n    > img,\n    > a > img {\n      &:extend(.img-responsive);\n      line-height: 1;\n    }\n  }\n\n  > .active,\n  > .next,\n  > .prev { display: block; }\n\n  > .active {\n    left: 0;\n  }\n\n  > .next,\n  > .prev {\n    position: absolute;\n    top: 0;\n    width: 100%;\n  }\n\n  > .next {\n    left: 100%;\n  }\n  > .prev {\n    left: -100%;\n  }\n  > .next.left,\n  > .prev.right {\n    left: 0;\n  }\n\n  > .active.left {\n    left: -100%;\n  }\n  > .active.right {\n    left: 100%;\n  }\n\n}\n\n// Left/right controls for nav\n// ---------------------------\n\n.carousel-control {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  width: @carousel-control-width;\n  .opacity(@carousel-control-opacity);\n  font-size: @carousel-control-font-size;\n  color: @carousel-control-color;\n  text-align: center;\n  text-shadow: @carousel-text-shadow;\n  // We can't have this transition here because WebKit cancels the carousel\n  // animation if you trip this while in the middle of another animation.\n\n  // Set gradients for backgrounds\n  &.left {\n    #gradient > .horizontal(@start-color: rgba(0,0,0,.5); @end-color: rgba(0,0,0,.0001));\n  }\n  &.right {\n    left: auto;\n    right: 0;\n    #gradient > .horizontal(@start-color: rgba(0,0,0,.0001); @end-color: rgba(0,0,0,.5));\n  }\n\n  // Hover/focus state\n  &:hover,\n  &:focus {\n    outline: none;\n    color: @carousel-control-color;\n    text-decoration: none;\n    .opacity(.9);\n  }\n\n  // Toggles\n  .icon-prev,\n  .icon-next,\n  .glyphicon-chevron-left,\n  .glyphicon-chevron-right {\n    position: absolute;\n    top: 50%;\n    z-index: 5;\n    display: inline-block;\n  }\n  .icon-prev,\n  .glyphicon-chevron-left {\n    left: 50%;\n  }\n  .icon-next,\n  .glyphicon-chevron-right {\n    right: 50%;\n  }\n  .icon-prev,\n  .icon-next {\n    width:  20px;\n    height: 20px;\n    margin-top: -10px;\n    margin-left: -10px;\n    font-family: serif;\n  }\n\n  .icon-prev {\n    &:before {\n      content: '\\2039';// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039)\n    }\n  }\n  .icon-next {\n    &:before {\n      content: '\\203a';// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A)\n    }\n  }\n}\n\n// Optional indicator pips\n//\n// Add an unordered list with the following class and add a list item for each\n// slide your carousel holds.\n\n.carousel-indicators {\n  position: absolute;\n  bottom: 10px;\n  left: 50%;\n  z-index: 15;\n  width: 60%;\n  margin-left: -30%;\n  padding-left: 0;\n  list-style: none;\n  text-align: center;\n\n  li {\n    display: inline-block;\n    width:  10px;\n    height: 10px;\n    margin: 1px;\n    text-indent: -999px;\n    border: 1px solid @carousel-indicator-border-color;\n    border-radius: 10px;\n    cursor: pointer;\n\n    // IE8-9 hack for event handling\n    //\n    // Internet Explorer 8-9 does not support clicks on elements without a set\n    // `background-color`. We cannot use `filter` since that's not viewed as a\n    // background color by the browser. Thus, a hack is needed.\n    //\n    // For IE8, we set solid black as it doesn't support `rgba()`. For IE9, we\n    // set alpha transparency for the best results possible.\n    background-color: #000 \\9; // IE8\n    background-color: rgba(0,0,0,0); // IE9\n  }\n  .active {\n    margin: 0;\n    width:  12px;\n    height: 12px;\n    background-color: @carousel-indicator-active-bg;\n  }\n}\n\n// Optional captions\n// -----------------------------\n// Hidden by default for smaller viewports\n.carousel-caption {\n  position: absolute;\n  left: 15%;\n  right: 15%;\n  bottom: 20px;\n  z-index: 10;\n  padding-top: 20px;\n  padding-bottom: 20px;\n  color: @carousel-caption-color;\n  text-align: center;\n  text-shadow: @carousel-text-shadow;\n  & .btn {\n    text-shadow: none; // No shadow for button elements in carousel-caption\n  }\n}\n\n\n// Scale up controls for tablets and up\n@media screen and (min-width: @screen-sm-min) {\n\n  // Scale up the controls a smidge\n  .carousel-control {\n    .glyphicon-chevron-left,\n    .glyphicon-chevron-right,\n    .icon-prev,\n    .icon-next {\n      width: 30px;\n      height: 30px;\n      margin-top: -15px;\n      margin-left: -15px;\n      font-size: 30px;\n    }\n  }\n\n  // Show and left align the captions\n  .carousel-caption {\n    left: 20%;\n    right: 20%;\n    padding-bottom: 30px;\n  }\n\n  // Move up the indicators\n  .carousel-indicators {\n    bottom: 20px;\n  }\n}\n","//\n// Typography\n// --------------------------------------------------\n\n\n// Headings\n// -------------------------\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n  font-family: @headings-font-family;\n  font-weight: @headings-font-weight;\n  line-height: @headings-line-height;\n  color: @headings-color;\n\n  small,\n  .small {\n    font-weight: normal;\n    line-height: 1;\n    color: @headings-small-color;\n  }\n}\n\nh1, .h1,\nh2, .h2,\nh3, .h3 {\n  margin-top: @line-height-computed;\n  margin-bottom: (@line-height-computed / 2);\n\n  small,\n  .small {\n    font-size: 65%;\n  }\n}\nh4, .h4,\nh5, .h5,\nh6, .h6 {\n  margin-top: (@line-height-computed / 2);\n  margin-bottom: (@line-height-computed / 2);\n\n  small,\n  .small {\n    font-size: 75%;\n  }\n}\n\nh1, .h1 { font-size: @font-size-h1; }\nh2, .h2 { font-size: @font-size-h2; }\nh3, .h3 { font-size: @font-size-h3; }\nh4, .h4 { font-size: @font-size-h4; }\nh5, .h5 { font-size: @font-size-h5; }\nh6, .h6 { font-size: @font-size-h6; }\n\n\n// Body text\n// -------------------------\n\np {\n  margin: 0 0 (@line-height-computed / 2);\n}\n\n.lead {\n  margin-bottom: @line-height-computed;\n  font-size: floor((@font-size-base * 1.15));\n  font-weight: 200;\n  line-height: 1.4;\n\n  @media (min-width: @screen-sm-min) {\n    font-size: (@font-size-base * 1.5);\n  }\n}\n\n\n// Emphasis & misc\n// -------------------------\n\n// Ex: 14px base font * 85% = about 12px\nsmall,\n.small  { font-size: 85%; }\n\n// Undo browser default styling\ncite    { font-style: normal; }\n\n// Alignment\n.text-left           { text-align: left; }\n.text-right          { text-align: right; }\n.text-center         { text-align: center; }\n.text-justify        { text-align: justify; }\n\n// Contextual colors\n.text-muted {\n  color: @text-muted;\n}\n.text-primary {\n  .text-emphasis-variant(@brand-primary);\n}\n.text-success {\n  .text-emphasis-variant(@state-success-text);\n}\n.text-info {\n  .text-emphasis-variant(@state-info-text);\n}\n.text-warning {\n  .text-emphasis-variant(@state-warning-text);\n}\n.text-danger {\n  .text-emphasis-variant(@state-danger-text);\n}\n\n// Contextual backgrounds\n// For now we'll leave these alongside the text classes until v4 when we can\n// safely shift things around (per SemVer rules).\n.bg-primary {\n  // Given the contrast here, this is the only class to have its color inverted\n  // automatically.\n  color: #fff;\n  .bg-variant(@brand-primary);\n}\n.bg-success {\n  .bg-variant(@state-success-bg);\n}\n.bg-info {\n  .bg-variant(@state-info-bg);\n}\n.bg-warning {\n  .bg-variant(@state-warning-bg);\n}\n.bg-danger {\n  .bg-variant(@state-danger-bg);\n}\n\n\n// Page header\n// -------------------------\n\n.page-header {\n  padding-bottom: ((@line-height-computed / 2) - 1);\n  margin: (@line-height-computed * 2) 0 @line-height-computed;\n  border-bottom: 1px solid @page-header-border-color;\n}\n\n\n// Lists\n// --------------------------------------------------\n\n// Unordered and Ordered lists\nul,\nol {\n  margin-top: 0;\n  margin-bottom: (@line-height-computed / 2);\n  ul,\n  ol {\n    margin-bottom: 0;\n  }\n}\n\n// List options\n\n// Unstyled keeps list items block level, just removes default browser padding and list-style\n.list-unstyled {\n  padding-left: 0;\n  list-style: none;\n}\n\n// Inline turns list items into inline-block\n.list-inline {\n  .list-unstyled();\n  margin-left: -5px;\n\n  > li {\n    display: inline-block;\n    padding-left: 5px;\n    padding-right: 5px;\n  }\n}\n\n// Description Lists\ndl {\n  margin-top: 0; // Remove browser default\n  margin-bottom: @line-height-computed;\n}\ndt,\ndd {\n  line-height: @line-height-base;\n}\ndt {\n  font-weight: bold;\n}\ndd {\n  margin-left: 0; // Undo browser default\n}\n\n// Horizontal description lists\n//\n// Defaults to being stacked without any of the below styles applied, until the\n// grid breakpoint is reached (default of ~768px).\n\n@media (min-width: @grid-float-breakpoint) {\n  .dl-horizontal {\n    dt {\n      float: left;\n      width: (@component-offset-horizontal - 20);\n      clear: left;\n      text-align: right;\n      .text-overflow();\n    }\n    dd {\n      margin-left: @component-offset-horizontal;\n      &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present\n    }\n  }\n}\n\n// MISC\n// ----\n\n// Abbreviations and acronyms\nabbr[title],\n// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257\nabbr[data-original-title] {\n  cursor: help;\n  border-bottom: 1px dotted @abbr-border-color;\n}\n.initialism {\n  font-size: 90%;\n  text-transform: uppercase;\n}\n\n// Blockquotes\nblockquote {\n  padding: (@line-height-computed / 2) @line-height-computed;\n  margin: 0 0 @line-height-computed;\n  font-size: @blockquote-font-size;\n  border-left: 5px solid @blockquote-border-color;\n\n  p,\n  ul,\n  ol {\n    &:last-child {\n      margin-bottom: 0;\n    }\n  }\n\n  // Note: Deprecated small and .small as of v3.1.0\n  // Context: https://github.com/twbs/bootstrap/issues/11660\n  footer,\n  small,\n  .small {\n    display: block;\n    font-size: 80%; // back to default font-size\n    line-height: @line-height-base;\n    color: @blockquote-small-color;\n\n    &:before {\n      content: '\\2014 \\00A0'; // em dash, nbsp\n    }\n  }\n}\n\n// Opposite alignment of blockquote\n//\n// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0.\n.blockquote-reverse,\nblockquote.pull-right {\n  padding-right: 15px;\n  padding-left: 0;\n  border-right: 5px solid @blockquote-border-color;\n  border-left: 0;\n  text-align: right;\n\n  // Account for citation\n  footer,\n  small,\n  .small {\n    &:before { content: ''; }\n    &:after {\n      content: '\\00A0 \\2014'; // nbsp, em dash\n    }\n  }\n}\n\n// Quotes\nblockquote:before,\nblockquote:after {\n  content: \"\";\n}\n\n// Addresses\naddress {\n  margin-bottom: @line-height-computed;\n  font-style: normal;\n  line-height: @line-height-base;\n}\n","//\n// Code (inline and block)\n// --------------------------------------------------\n\n\n// Inline and block code styles\ncode,\nkbd,\npre,\nsamp {\n  font-family: @font-family-monospace;\n}\n\n// Inline code\ncode {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: @code-color;\n  background-color: @code-bg;\n  white-space: nowrap;\n  border-radius: @border-radius-base;\n}\n\n// User input typically entered via keyboard\nkbd {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: @kbd-color;\n  background-color: @kbd-bg;\n  border-radius: @border-radius-small;\n  box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);\n}\n\n// Blocks of code\npre {\n  display: block;\n  padding: ((@line-height-computed - 1) / 2);\n  margin: 0 0 (@line-height-computed / 2);\n  font-size: (@font-size-base - 1); // 14px to 13px\n  line-height: @line-height-base;\n  word-break: break-all;\n  word-wrap: break-word;\n  color: @pre-color;\n  background-color: @pre-bg;\n  border: 1px solid @pre-border-color;\n  border-radius: @border-radius-base;\n\n  // Account for some code outputs that place code tags in pre tags\n  code {\n    padding: 0;\n    font-size: inherit;\n    color: inherit;\n    white-space: pre-wrap;\n    background-color: transparent;\n    border-radius: 0;\n  }\n}\n\n// Enable scrollable blocks of code\n.pre-scrollable {\n  max-height: @pre-scrollable-max-height;\n  overflow-y: scroll;\n}\n","//\n// Grid system\n// --------------------------------------------------\n\n\n// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n.container {\n  .container-fixed();\n\n  @media (min-width: @screen-sm-min) {\n    width: @container-sm;\n  }\n  @media (min-width: @screen-md-min) {\n    width: @container-md;\n  }\n  @media (min-width: @screen-lg-min) {\n    width: @container-lg;\n  }\n}\n\n\n// Fluid container\n//\n// Utilizes the mixin meant for fixed width containers, but without any defined\n// width for fluid, full width layouts.\n\n.container-fluid {\n  .container-fixed();\n}\n\n\n// Row\n//\n// Rows contain and clear the floats of your columns.\n\n.row {\n  .make-row();\n}\n\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n.make-grid-columns();\n\n\n// Extra small grid\n//\n// Columns, offsets, pushes, and pulls for extra small devices like\n// smartphones.\n\n.make-grid(xs);\n\n\n// Small grid\n//\n// Columns, offsets, pushes, and pulls for the small device range, from phones\n// to tablets.\n\n@media (min-width: @screen-sm-min) {\n  .make-grid(sm);\n}\n\n\n// Medium grid\n//\n// Columns, offsets, pushes, and pulls for the desktop device range.\n\n@media (min-width: @screen-md-min) {\n  .make-grid(md);\n}\n\n\n// Large grid\n//\n// Columns, offsets, pushes, and pulls for the large desktop device range.\n\n@media (min-width: @screen-lg-min) {\n  .make-grid(lg);\n}\n","//\n// Tables\n// --------------------------------------------------\n\n\ntable {\n  max-width: 100%;\n  background-color: @table-bg;\n}\nth {\n  text-align: left;\n}\n\n\n// Baseline styles\n\n.table {\n  width: 100%;\n  margin-bottom: @line-height-computed;\n  // Cells\n  > thead,\n  > tbody,\n  > tfoot {\n    > tr {\n      > th,\n      > td {\n        padding: @table-cell-padding;\n        line-height: @line-height-base;\n        vertical-align: top;\n        border-top: 1px solid @table-border-color;\n      }\n    }\n  }\n  // Bottom align for column headings\n  > thead > tr > th {\n    vertical-align: bottom;\n    border-bottom: 2px solid @table-border-color;\n  }\n  // Remove top border from thead by default\n  > caption + thead,\n  > colgroup + thead,\n  > thead:first-child {\n    > tr:first-child {\n      > th,\n      > td {\n        border-top: 0;\n      }\n    }\n  }\n  // Account for multiple tbody instances\n  > tbody + tbody {\n    border-top: 2px solid @table-border-color;\n  }\n\n  // Nesting\n  .table {\n    background-color: @body-bg;\n  }\n}\n\n\n// Condensed table w/ half padding\n\n.table-condensed {\n  > thead,\n  > tbody,\n  > tfoot {\n    > tr {\n      > th,\n      > td {\n        padding: @table-condensed-cell-padding;\n      }\n    }\n  }\n}\n\n\n// Bordered version\n//\n// Add borders all around the table and between all the columns.\n\n.table-bordered {\n  border: 1px solid @table-border-color;\n  > thead,\n  > tbody,\n  > tfoot {\n    > tr {\n      > th,\n      > td {\n        border: 1px solid @table-border-color;\n      }\n    }\n  }\n  > thead > tr {\n    > th,\n    > td {\n      border-bottom-width: 2px;\n    }\n  }\n}\n\n\n// Zebra-striping\n//\n// Default zebra-stripe styles (alternating gray and transparent backgrounds)\n\n.table-striped {\n  > tbody > tr:nth-child(odd) {\n    > td,\n    > th {\n      background-color: @table-bg-accent;\n    }\n  }\n}\n\n\n// Hover effect\n//\n// Placed here since it has to come after the potential zebra striping\n\n.table-hover {\n  > tbody > tr:hover {\n    > td,\n    > th {\n      background-color: @table-bg-hover;\n    }\n  }\n}\n\n\n// Table cell sizing\n//\n// Reset default table behavior\n\ntable col[class*=\"col-\"] {\n  position: static; // Prevent border hiding in Firefox and IE9/10 (see https://github.com/twbs/bootstrap/issues/11623)\n  float: none;\n  display: table-column;\n}\ntable {\n  td,\n  th {\n    &[class*=\"col-\"] {\n      position: static; // Prevent border hiding in Firefox and IE9/10 (see https://github.com/twbs/bootstrap/issues/11623)\n      float: none;\n      display: table-cell;\n    }\n  }\n}\n\n\n// Table backgrounds\n//\n// Exact selectors below required to override `.table-striped` and prevent\n// inheritance to nested tables.\n\n// Generate the contextual variants\n.table-row-variant(active; @table-bg-active);\n.table-row-variant(success; @state-success-bg);\n.table-row-variant(info; @state-info-bg);\n.table-row-variant(warning; @state-warning-bg);\n.table-row-variant(danger; @state-danger-bg);\n\n\n// Responsive tables\n//\n// Wrap your tables in `.table-responsive` and we'll make them mobile friendly\n// by enabling horizontal scrolling. Only applies <768px. Everything above that\n// will display normally.\n\n@media (max-width: @screen-xs-max) {\n  .table-responsive {\n    width: 100%;\n    margin-bottom: (@line-height-computed * 0.75);\n    overflow-y: hidden;\n    overflow-x: scroll;\n    -ms-overflow-style: -ms-autohiding-scrollbar;\n    border: 1px solid @table-border-color;\n    -webkit-overflow-scrolling: touch;\n\n    // Tighten up spacing\n    > .table {\n      margin-bottom: 0;\n\n      // Ensure the content doesn't wrap\n      > thead,\n      > tbody,\n      > tfoot {\n        > tr {\n          > th,\n          > td {\n            white-space: nowrap;\n          }\n        }\n      }\n    }\n\n    // Special overrides for the bordered tables\n    > .table-bordered {\n      border: 0;\n\n      // Nuke the appropriate borders so that the parent can handle them\n      > thead,\n      > tbody,\n      > tfoot {\n        > tr {\n          > th:first-child,\n          > td:first-child {\n            border-left: 0;\n          }\n          > th:last-child,\n          > td:last-child {\n            border-right: 0;\n          }\n        }\n      }\n\n      // Only nuke the last row's bottom-border in `tbody` and `tfoot` since\n      // chances are there will be only one `tr` in a `thead` and that would\n      // remove the border altogether.\n      > tbody,\n      > tfoot {\n        > tr:last-child {\n          > th,\n          > td {\n            border-bottom: 0;\n          }\n        }\n      }\n\n    }\n  }\n}\n","//\n// Forms\n// --------------------------------------------------\n\n\n// Normalize non-controls\n//\n// Restyle and baseline non-control form elements.\n\nfieldset {\n  padding: 0;\n  margin: 0;\n  border: 0;\n  // Chrome and Firefox set a `min-width: -webkit-min-content;` on fieldsets,\n  // so we reset that to ensure it behaves more like a standard block element.\n  // See https://github.com/twbs/bootstrap/issues/12359.\n  min-width: 0;\n}\n\nlegend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: @line-height-computed;\n  font-size: (@font-size-base * 1.5);\n  line-height: inherit;\n  color: @legend-color;\n  border: 0;\n  border-bottom: 1px solid @legend-border-color;\n}\n\nlabel {\n  display: inline-block;\n  margin-bottom: 5px;\n  font-weight: bold;\n}\n\n\n// Normalize form controls\n//\n// While most of our form styles require extra classes, some basic normalization\n// is required to ensure optimum display with or without those classes to better\n// address browser inconsistencies.\n\n// Override content-box in Normalize (* isn't specific enough)\ninput[type=\"search\"] {\n  .box-sizing(border-box);\n}\n\n// Position radios and checkboxes better\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  margin: 4px 0 0;\n  margin-top: 1px \\9; /* IE8-9 */\n  line-height: normal;\n}\n\n// Set the height of file controls to match text inputs\ninput[type=\"file\"] {\n  display: block;\n}\n\n// Make range inputs behave like textual form controls\ninput[type=\"range\"] {\n  display: block;\n  width: 100%;\n}\n\n// Make multiple select elements height not fixed\nselect[multiple],\nselect[size] {\n  height: auto;\n}\n\n// Focus for file, radio, and checkbox\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n  .tab-focus();\n}\n\n// Adjust output element\noutput {\n  display: block;\n  padding-top: (@padding-base-vertical + 1);\n  font-size: @font-size-base;\n  line-height: @line-height-base;\n  color: @input-color;\n}\n\n\n// Common form controls\n//\n// Shared size and type resets for form controls. Apply `.form-control` to any\n// of the following form controls:\n//\n// select\n// textarea\n// input[type=\"text\"]\n// input[type=\"password\"]\n// input[type=\"datetime\"]\n// input[type=\"datetime-local\"]\n// input[type=\"date\"]\n// input[type=\"month\"]\n// input[type=\"time\"]\n// input[type=\"week\"]\n// input[type=\"number\"]\n// input[type=\"email\"]\n// input[type=\"url\"]\n// input[type=\"search\"]\n// input[type=\"tel\"]\n// input[type=\"color\"]\n\n.form-control {\n  display: block;\n  width: 100%;\n  height: @input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border)\n  padding: @padding-base-vertical @padding-base-horizontal;\n  font-size: @font-size-base;\n  line-height: @line-height-base;\n  color: @input-color;\n  background-color: @input-bg;\n  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n  border: 1px solid @input-border;\n  border-radius: @input-border-radius;\n  .box-shadow(inset 0 1px 1px rgba(0,0,0,.075));\n  .transition(~\"border-color ease-in-out .15s, box-shadow ease-in-out .15s\");\n\n  // Customize the `:focus` state to imitate native WebKit styles.\n  .form-control-focus();\n\n  // Placeholder\n  .placeholder();\n\n  // Disabled and read-only inputs\n  //\n  // HTML5 says that controls under a fieldset > legend:first-child won't be\n  // disabled if the fieldset is disabled. Due to implementation difficulty, we\n  // don't honor that edge case; we style them as disabled anyway.\n  &[disabled],\n  &[readonly],\n  fieldset[disabled] & {\n    cursor: not-allowed;\n    background-color: @input-bg-disabled;\n    opacity: 1; // iOS fix for unreadable disabled content\n  }\n\n  // Reset height for `textarea`s\n  textarea& {\n    height: auto;\n  }\n}\n\n\n// Search inputs in iOS\n//\n// This overrides the extra rounded corners on search inputs in iOS so that our\n// `.form-control` class can properly style them. Note that this cannot simply\n// be added to `.form-control` as it's not specific enough. For details, see\n// https://github.com/twbs/bootstrap/issues/11586.\n\ninput[type=\"search\"] {\n  -webkit-appearance: none;\n}\n\n\n// Special styles for iOS date input\n//\n// In Mobile Safari, date inputs require a pixel line-height that matches the\n// given height of the input.\n\ninput[type=\"date\"] {\n  line-height: @input-height-base;\n}\n\n\n// Form groups\n//\n// Designed to help with the organization and spacing of vertical forms. For\n// horizontal forms, use the predefined grid classes.\n\n.form-group {\n  margin-bottom: 15px;\n}\n\n\n// Checkboxes and radios\n//\n// Indent the labels to position radios/checkboxes as hanging controls.\n\n.radio,\n.checkbox {\n  display: block;\n  min-height: @line-height-computed; // clear the floating input if there is no label text\n  margin-top: 10px;\n  margin-bottom: 10px;\n  padding-left: 20px;\n  label {\n    display: inline;\n    font-weight: normal;\n    cursor: pointer;\n  }\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n  float: left;\n  margin-left: -20px;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n  margin-top: -5px; // Move up sibling radios or checkboxes for tighter spacing\n}\n\n// Radios and checkboxes on same line\n.radio-inline,\n.checkbox-inline {\n  display: inline-block;\n  padding-left: 20px;\n  margin-bottom: 0;\n  vertical-align: middle;\n  font-weight: normal;\n  cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n  margin-top: 0;\n  margin-left: 10px; // space out consecutive inline controls\n}\n\n// Apply same disabled cursor tweak as for inputs\n//\n// Note: Neither radios nor checkboxes can be readonly.\ninput[type=\"radio\"],\ninput[type=\"checkbox\"],\n.radio,\n.radio-inline,\n.checkbox,\n.checkbox-inline {\n  &[disabled],\n  fieldset[disabled] & {\n    cursor: not-allowed;\n  }\n}\n\n\n// Form control sizing\n//\n// Build on `.form-control` with modifier classes to decrease or increase the\n// height and font-size of form controls.\n\n.input-sm {\n  .input-size(@input-height-small; @padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n\n.input-lg {\n  .input-size(@input-height-large; @padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);\n}\n\n\n// Form control feedback states\n//\n// Apply contextual and semantic states to individual form controls.\n\n.has-feedback {\n  // Enable absolute positioning\n  position: relative;\n\n  // Ensure icons don't overlap text\n  .form-control {\n    padding-right: (@input-height-base * 1.25);\n  }\n\n  // Feedback icon (requires .glyphicon classes)\n  .form-control-feedback {\n    position: absolute;\n    top: (@line-height-computed + 5); // Height of the `label` and its margin\n    right: 0;\n    display: block;\n    width: @input-height-base;\n    height: @input-height-base;\n    line-height: @input-height-base;\n    text-align: center;\n  }\n}\n\n// Feedback states\n.has-success {\n  .form-control-validation(@state-success-text; @state-success-text; @state-success-bg);\n}\n.has-warning {\n  .form-control-validation(@state-warning-text; @state-warning-text; @state-warning-bg);\n}\n.has-error {\n  .form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg);\n}\n\n\n// Static form control text\n//\n// Apply class to a `p` element to make any string of text align with labels in\n// a horizontal form layout.\n\n.form-control-static {\n  margin-bottom: 0; // Remove default margin from `p`\n}\n\n\n// Help text\n//\n// Apply to any element you wish to create light text for placement immediately\n// below a form control. Use for general help, formatting, or instructional text.\n\n.help-block {\n  display: block; // account for any element using help-block\n  margin-top: 5px;\n  margin-bottom: 10px;\n  color: lighten(@text-color, 25%); // lighten the text some for contrast\n}\n\n\n\n// Inline forms\n//\n// Make forms appear inline(-block) by adding the `.form-inline` class. Inline\n// forms begin stacked on extra small (mobile) devices and then go inline when\n// viewports reach <768px.\n//\n// Requires wrapping inputs and labels with `.form-group` for proper display of\n// default HTML form controls and our custom form controls (e.g., input groups).\n//\n// Heads up! This is mixin-ed into `.navbar-form` in navbars.less.\n\n.form-inline {\n\n  // Kick in the inline\n  @media (min-width: @screen-sm-min) {\n    // Inline-block all the things for \"inline\"\n    .form-group {\n      display: inline-block;\n      margin-bottom: 0;\n      vertical-align: middle;\n    }\n\n    // In navbar-form, allow folks to *not* use `.form-group`\n    .form-control {\n      display: inline-block;\n      width: auto; // Prevent labels from stacking above inputs in `.form-group`\n      vertical-align: middle;\n    }\n    // Input groups need that 100% width though\n    .input-group > .form-control {\n      width: 100%;\n    }\n\n    .control-label {\n      margin-bottom: 0;\n      vertical-align: middle;\n    }\n\n    // Remove default margin on radios/checkboxes that were used for stacking, and\n    // then undo the floating of radios and checkboxes to match (which also avoids\n    // a bug in WebKit: https://github.com/twbs/bootstrap/issues/1969).\n    .radio,\n    .checkbox {\n      display: inline-block;\n      margin-top: 0;\n      margin-bottom: 0;\n      padding-left: 0;\n      vertical-align: middle;\n    }\n    .radio input[type=\"radio\"],\n    .checkbox input[type=\"checkbox\"] {\n      float: none;\n      margin-left: 0;\n    }\n\n    // Validation states\n    //\n    // Reposition the icon because it's now within a grid column and columns have\n    // `position: relative;` on them. Also accounts for the grid gutter padding.\n    .has-feedback .form-control-feedback {\n      top: 0;\n    }\n  }\n}\n\n\n// Horizontal forms\n//\n// Horizontal forms are built on grid classes and allow you to create forms with\n// labels on the left and inputs on the right.\n\n.form-horizontal {\n\n  // Consistent vertical alignment of labels, radios, and checkboxes\n  .control-label,\n  .radio,\n  .checkbox,\n  .radio-inline,\n  .checkbox-inline {\n    margin-top: 0;\n    margin-bottom: 0;\n    padding-top: (@padding-base-vertical + 1); // Default padding plus a border\n  }\n  // Account for padding we're adding to ensure the alignment and of help text\n  // and other content below items\n  .radio,\n  .checkbox {\n    min-height: (@line-height-computed + (@padding-base-vertical + 1));\n  }\n\n  // Make form groups behave like rows\n  .form-group {\n    .make-row();\n  }\n\n  .form-control-static {\n    padding-top: (@padding-base-vertical + 1);\n  }\n\n  // Only right align form labels here when the columns stop stacking\n  @media (min-width: @screen-sm-min) {\n    .control-label {\n      text-align: right;\n    }\n  }\n\n  // Validation states\n  //\n  // Reposition the icon because it's now within a grid column and columns have\n  // `position: relative;` on them. Also accounts for the grid gutter padding.\n  .has-feedback .form-control-feedback {\n    top: 0;\n    right: (@grid-gutter-width / 2);\n  }\n}\n","//\n// Buttons\n// --------------------------------------------------\n\n\n// Base styles\n// --------------------------------------------------\n\n.btn {\n  display: inline-block;\n  margin-bottom: 0; // For input.btn\n  font-weight: @btn-font-weight;\n  text-align: center;\n  vertical-align: middle;\n  cursor: pointer;\n  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n  border: 1px solid transparent;\n  white-space: nowrap;\n  .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @border-radius-base);\n  .user-select(none);\n\n  &,\n  &:active,\n  &.active {\n    &:focus {\n      .tab-focus();\n    }\n  }\n\n  &:hover,\n  &:focus {\n    color: @btn-default-color;\n    text-decoration: none;\n  }\n\n  &:active,\n  &.active {\n    outline: 0;\n    background-image: none;\n    .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n  }\n\n  &.disabled,\n  &[disabled],\n  fieldset[disabled] & {\n    cursor: not-allowed;\n    pointer-events: none; // Future-proof disabling of clicks\n    .opacity(.65);\n    .box-shadow(none);\n  }\n}\n\n\n// Alternate buttons\n// --------------------------------------------------\n\n.btn-default {\n  .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border);\n}\n.btn-primary {\n  .button-variant(@btn-primary-color; @btn-primary-bg; @btn-primary-border);\n}\n// Success appears as green\n.btn-success {\n  .button-variant(@btn-success-color; @btn-success-bg; @btn-success-border);\n}\n// Info appears as blue-green\n.btn-info {\n  .button-variant(@btn-info-color; @btn-info-bg; @btn-info-border);\n}\n// Warning appears as orange\n.btn-warning {\n  .button-variant(@btn-warning-color; @btn-warning-bg; @btn-warning-border);\n}\n// Danger and error appear as red\n.btn-danger {\n  .button-variant(@btn-danger-color; @btn-danger-bg; @btn-danger-border);\n}\n\n\n// Link buttons\n// -------------------------\n\n// Make a button look and behave like a link\n.btn-link {\n  color: @link-color;\n  font-weight: normal;\n  cursor: pointer;\n  border-radius: 0;\n\n  &,\n  &:active,\n  &[disabled],\n  fieldset[disabled] & {\n    background-color: transparent;\n    .box-shadow(none);\n  }\n  &,\n  &:hover,\n  &:focus,\n  &:active {\n    border-color: transparent;\n  }\n  &:hover,\n  &:focus {\n    color: @link-hover-color;\n    text-decoration: underline;\n    background-color: transparent;\n  }\n  &[disabled],\n  fieldset[disabled] & {\n    &:hover,\n    &:focus {\n      color: @btn-link-disabled-color;\n      text-decoration: none;\n    }\n  }\n}\n\n\n// Button Sizes\n// --------------------------------------------------\n\n.btn-lg {\n  // line-height: ensure even-numbered height of button next to large input\n  .button-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);\n}\n.btn-sm {\n  // line-height: ensure proper height of button next to small input\n  .button-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n.btn-xs {\n  .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n\n\n// Block button\n// --------------------------------------------------\n\n.btn-block {\n  display: block;\n  width: 100%;\n  padding-left: 0;\n  padding-right: 0;\n}\n\n// Vertically space out multiple block buttons\n.btn-block + .btn-block {\n  margin-top: 5px;\n}\n\n// Specificity overrides\ninput[type=\"submit\"],\ninput[type=\"reset\"],\ninput[type=\"button\"] {\n  &.btn-block {\n    width: 100%;\n  }\n}\n","//\n// Button groups\n// --------------------------------------------------\n\n// Make the div behave like a button\n.btn-group,\n.btn-group-vertical {\n  position: relative;\n  display: inline-block;\n  vertical-align: middle; // match .btn alignment given font-size hack above\n  > .btn {\n    position: relative;\n    float: left;\n    // Bring the \"active\" button to the front\n    &:hover,\n    &:focus,\n    &:active,\n    &.active {\n      z-index: 2;\n    }\n    &:focus {\n      // Remove focus outline when dropdown JS adds it after closing the menu\n      outline: none;\n    }\n  }\n}\n\n// Prevent double borders when buttons are next to each other\n.btn-group {\n  .btn + .btn,\n  .btn + .btn-group,\n  .btn-group + .btn,\n  .btn-group + .btn-group {\n    margin-left: -1px;\n  }\n}\n\n// Optional: Group multiple button groups together for a toolbar\n.btn-toolbar {\n  margin-left: -5px; // Offset the first child's margin\n  &:extend(.clearfix all);\n\n  .btn-group,\n  .input-group {\n    float: left;\n  }\n  > .btn,\n  > .btn-group,\n  > .input-group {\n    margin-left: 5px;\n  }\n}\n\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n  border-radius: 0;\n}\n\n// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match\n.btn-group > .btn:first-child {\n  margin-left: 0;\n  &:not(:last-child):not(.dropdown-toggle) {\n    .border-right-radius(0);\n  }\n}\n// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n  .border-left-radius(0);\n}\n\n// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group)\n.btn-group > .btn-group {\n  float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group > .btn-group:first-child {\n  > .btn:last-child,\n  > .dropdown-toggle {\n    .border-right-radius(0);\n  }\n}\n.btn-group > .btn-group:last-child > .btn:first-child {\n  .border-left-radius(0);\n}\n\n// On active and open, don't show outline\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n  outline: 0;\n}\n\n\n// Sizing\n//\n// Remix the default button sizing classes into new ones for easier manipulation.\n\n.btn-group-xs > .btn { &:extend(.btn-xs); }\n.btn-group-sm > .btn { &:extend(.btn-sm); }\n.btn-group-lg > .btn { &:extend(.btn-lg); }\n\n\n// Split button dropdowns\n// ----------------------\n\n// Give the line between buttons some depth\n.btn-group > .btn + .dropdown-toggle {\n  padding-left: 8px;\n  padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n  padding-left: 12px;\n  padding-right: 12px;\n}\n\n// The clickable button for toggling the menu\n// Remove the gradient and set the same inset shadow as the :active state\n.btn-group.open .dropdown-toggle {\n  .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n\n  // Show no shadow for `.btn-link` since it has no other button styles.\n  &.btn-link {\n    .box-shadow(none);\n  }\n}\n\n\n// Reposition the caret\n.btn .caret {\n  margin-left: 0;\n}\n// Carets in other button sizes\n.btn-lg .caret {\n  border-width: @caret-width-large @caret-width-large 0;\n  border-bottom-width: 0;\n}\n// Upside down carets for .dropup\n.dropup .btn-lg .caret {\n  border-width: 0 @caret-width-large @caret-width-large;\n}\n\n\n// Vertical button groups\n// ----------------------\n\n.btn-group-vertical {\n  > .btn,\n  > .btn-group,\n  > .btn-group > .btn {\n    display: block;\n    float: none;\n    width: 100%;\n    max-width: 100%;\n  }\n\n  // Clear floats so dropdown menus can be properly placed\n  > .btn-group {\n    &:extend(.clearfix all);\n    > .btn {\n      float: none;\n    }\n  }\n\n  > .btn + .btn,\n  > .btn + .btn-group,\n  > .btn-group + .btn,\n  > .btn-group + .btn-group {\n    margin-top: -1px;\n    margin-left: 0;\n  }\n}\n\n.btn-group-vertical > .btn {\n  &:not(:first-child):not(:last-child) {\n    border-radius: 0;\n  }\n  &:first-child:not(:last-child) {\n    border-top-right-radius: @border-radius-base;\n    .border-bottom-radius(0);\n  }\n  &:last-child:not(:first-child) {\n    border-bottom-left-radius: @border-radius-base;\n    .border-top-radius(0);\n  }\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) {\n  > .btn:last-child,\n  > .dropdown-toggle {\n    .border-bottom-radius(0);\n  }\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  .border-top-radius(0);\n}\n\n\n\n// Justified button groups\n// ----------------------\n\n.btn-group-justified {\n  display: table;\n  width: 100%;\n  table-layout: fixed;\n  border-collapse: separate;\n  > .btn,\n  > .btn-group {\n    float: none;\n    display: table-cell;\n    width: 1%;\n  }\n  > .btn-group .btn {\n    width: 100%;\n  }\n}\n\n\n// Checkbox and radio options\n[data-toggle=\"buttons\"] > .btn > input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn > input[type=\"checkbox\"] {\n  display: none;\n}\n","//\n// Component animations\n// --------------------------------------------------\n\n// Heads up!\n//\n// We don't use the `.opacity()` mixin here since it causes a bug with text\n// fields in IE7-8. Source: https://github.com/twitter/bootstrap/pull/3552.\n\n.fade {\n  opacity: 0;\n  .transition(opacity .15s linear);\n  &.in {\n    opacity: 1;\n  }\n}\n\n.collapse {\n  display: none;\n  &.in {\n    display: block;\n  }\n}\n.collapsing {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  .transition(height .35s ease);\n}\n","//\n// Glyphicons for Bootstrap\n//\n// Since icons are fonts, they can be placed anywhere text is placed and are\n// thus automatically sized to match the surrounding child. To use, create an\n// inline element with the appropriate classes, like so:\n//\n//  Star\n\n// Import the fonts\n@font-face {\n  font-family: 'Glyphicons Halflings';\n  src: ~\"url('@{icon-font-path}@{icon-font-name}.eot')\";\n  src: ~\"url('@{icon-font-path}@{icon-font-name}.eot?#iefix') format('embedded-opentype')\",\n       ~\"url('@{icon-font-path}@{icon-font-name}.woff') format('woff')\",\n       ~\"url('@{icon-font-path}@{icon-font-name}.ttf') format('truetype')\",\n       ~\"url('@{icon-font-path}@{icon-font-name}.svg#@{icon-font-svg-id}') format('svg')\";\n}\n\n// Catchall baseclass\n.glyphicon {\n  position: relative;\n  top: 1px;\n  display: inline-block;\n  font-family: 'Glyphicons Halflings';\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\n// Individual icons\n.glyphicon-asterisk               { &:before { content: \"\\2a\"; } }\n.glyphicon-plus                   { &:before { content: \"\\2b\"; } }\n.glyphicon-euro                   { &:before { content: \"\\20ac\"; } }\n.glyphicon-minus                  { &:before { content: \"\\2212\"; } }\n.glyphicon-cloud                  { &:before { content: \"\\2601\"; } }\n.glyphicon-envelope               { &:before { content: \"\\2709\"; } }\n.glyphicon-pencil                 { &:before { content: \"\\270f\"; } }\n.glyphicon-glass                  { &:before { content: \"\\e001\"; } }\n.glyphicon-music                  { &:before { content: \"\\e002\"; } }\n.glyphicon-search                 { &:before { content: \"\\e003\"; } }\n.glyphicon-heart                  { &:before { content: \"\\e005\"; } }\n.glyphicon-star                   { &:before { content: \"\\e006\"; } }\n.glyphicon-star-empty             { &:before { content: \"\\e007\"; } }\n.glyphicon-user                   { &:before { content: \"\\e008\"; } }\n.glyphicon-film                   { &:before { content: \"\\e009\"; } }\n.glyphicon-th-large               { &:before { content: \"\\e010\"; } }\n.glyphicon-th                     { &:before { content: \"\\e011\"; } }\n.glyphicon-th-list                { &:before { content: \"\\e012\"; } }\n.glyphicon-ok                     { &:before { content: \"\\e013\"; } }\n.glyphicon-remove                 { &:before { content: \"\\e014\"; } }\n.glyphicon-zoom-in                { &:before { content: \"\\e015\"; } }\n.glyphicon-zoom-out               { &:before { content: \"\\e016\"; } }\n.glyphicon-off                    { &:before { content: \"\\e017\"; } }\n.glyphicon-signal                 { &:before { content: \"\\e018\"; } }\n.glyphicon-cog                    { &:before { content: \"\\e019\"; } }\n.glyphicon-trash                  { &:before { content: \"\\e020\"; } }\n.glyphicon-home                   { &:before { content: \"\\e021\"; } }\n.glyphicon-file                   { &:before { content: \"\\e022\"; } }\n.glyphicon-time                   { &:before { content: \"\\e023\"; } }\n.glyphicon-road                   { &:before { content: \"\\e024\"; } }\n.glyphicon-download-alt           { &:before { content: \"\\e025\"; } }\n.glyphicon-download               { &:before { content: \"\\e026\"; } }\n.glyphicon-upload                 { &:before { content: \"\\e027\"; } }\n.glyphicon-inbox                  { &:before { content: \"\\e028\"; } }\n.glyphicon-play-circle            { &:before { content: \"\\e029\"; } }\n.glyphicon-repeat                 { &:before { content: \"\\e030\"; } }\n.glyphicon-refresh                { &:before { content: \"\\e031\"; } }\n.glyphicon-list-alt               { &:before { content: \"\\e032\"; } }\n.glyphicon-lock                   { &:before { content: \"\\e033\"; } }\n.glyphicon-flag                   { &:before { content: \"\\e034\"; } }\n.glyphicon-headphones             { &:before { content: \"\\e035\"; } }\n.glyphicon-volume-off             { &:before { content: \"\\e036\"; } }\n.glyphicon-volume-down            { &:before { content: \"\\e037\"; } }\n.glyphicon-volume-up              { &:before { content: \"\\e038\"; } }\n.glyphicon-qrcode                 { &:before { content: \"\\e039\"; } }\n.glyphicon-barcode                { &:before { content: \"\\e040\"; } }\n.glyphicon-tag                    { &:before { content: \"\\e041\"; } }\n.glyphicon-tags                   { &:before { content: \"\\e042\"; } }\n.glyphicon-book                   { &:before { content: \"\\e043\"; } }\n.glyphicon-bookmark               { &:before { content: \"\\e044\"; } }\n.glyphicon-print                  { &:before { content: \"\\e045\"; } }\n.glyphicon-camera                 { &:before { content: \"\\e046\"; } }\n.glyphicon-font                   { &:before { content: \"\\e047\"; } }\n.glyphicon-bold                   { &:before { content: \"\\e048\"; } }\n.glyphicon-italic                 { &:before { content: \"\\e049\"; } }\n.glyphicon-text-height            { &:before { content: \"\\e050\"; } }\n.glyphicon-text-width             { &:before { content: \"\\e051\"; } }\n.glyphicon-align-left             { &:before { content: \"\\e052\"; } }\n.glyphicon-align-center           { &:before { content: \"\\e053\"; } }\n.glyphicon-align-right            { &:before { content: \"\\e054\"; } }\n.glyphicon-align-justify          { &:before { content: \"\\e055\"; } }\n.glyphicon-list                   { &:before { content: \"\\e056\"; } }\n.glyphicon-indent-left            { &:before { content: \"\\e057\"; } }\n.glyphicon-indent-right           { &:before { content: \"\\e058\"; } }\n.glyphicon-facetime-video         { &:before { content: \"\\e059\"; } }\n.glyphicon-picture                { &:before { content: \"\\e060\"; } }\n.glyphicon-map-marker             { &:before { content: \"\\e062\"; } }\n.glyphicon-adjust                 { &:before { content: \"\\e063\"; } }\n.glyphicon-tint                   { &:before { content: \"\\e064\"; } }\n.glyphicon-edit                   { &:before { content: \"\\e065\"; } }\n.glyphicon-share                  { &:before { content: \"\\e066\"; } }\n.glyphicon-check                  { &:before { content: \"\\e067\"; } }\n.glyphicon-move                   { &:before { content: \"\\e068\"; } }\n.glyphicon-step-backward          { &:before { content: \"\\e069\"; } }\n.glyphicon-fast-backward          { &:before { content: \"\\e070\"; } }\n.glyphicon-backward               { &:before { content: \"\\e071\"; } }\n.glyphicon-play                   { &:before { content: \"\\e072\"; } }\n.glyphicon-pause                  { &:before { content: \"\\e073\"; } }\n.glyphicon-stop                   { &:before { content: \"\\e074\"; } }\n.glyphicon-forward                { &:before { content: \"\\e075\"; } }\n.glyphicon-fast-forward           { &:before { content: \"\\e076\"; } }\n.glyphicon-step-forward           { &:before { content: \"\\e077\"; } }\n.glyphicon-eject                  { &:before { content: \"\\e078\"; } }\n.glyphicon-chevron-left           { &:before { content: \"\\e079\"; } }\n.glyphicon-chevron-right          { &:before { content: \"\\e080\"; } }\n.glyphicon-plus-sign              { &:before { content: \"\\e081\"; } }\n.glyphicon-minus-sign             { &:before { content: \"\\e082\"; } }\n.glyphicon-remove-sign            { &:before { content: \"\\e083\"; } }\n.glyphicon-ok-sign                { &:before { content: \"\\e084\"; } }\n.glyphicon-question-sign          { &:before { content: \"\\e085\"; } }\n.glyphicon-info-sign              { &:before { content: \"\\e086\"; } }\n.glyphicon-screenshot             { &:before { content: \"\\e087\"; } }\n.glyphicon-remove-circle          { &:before { content: \"\\e088\"; } }\n.glyphicon-ok-circle              { &:before { content: \"\\e089\"; } }\n.glyphicon-ban-circle             { &:before { content: \"\\e090\"; } }\n.glyphicon-arrow-left             { &:before { content: \"\\e091\"; } }\n.glyphicon-arrow-right            { &:before { content: \"\\e092\"; } }\n.glyphicon-arrow-up               { &:before { content: \"\\e093\"; } }\n.glyphicon-arrow-down             { &:before { content: \"\\e094\"; } }\n.glyphicon-share-alt              { &:before { content: \"\\e095\"; } }\n.glyphicon-resize-full            { &:before { content: \"\\e096\"; } }\n.glyphicon-resize-small           { &:before { content: \"\\e097\"; } }\n.glyphicon-exclamation-sign       { &:before { content: \"\\e101\"; } }\n.glyphicon-gift                   { &:before { content: \"\\e102\"; } }\n.glyphicon-leaf                   { &:before { content: \"\\e103\"; } }\n.glyphicon-fire                   { &:before { content: \"\\e104\"; } }\n.glyphicon-eye-open               { &:before { content: \"\\e105\"; } }\n.glyphicon-eye-close              { &:before { content: \"\\e106\"; } }\n.glyphicon-warning-sign           { &:before { content: \"\\e107\"; } }\n.glyphicon-plane                  { &:before { content: \"\\e108\"; } }\n.glyphicon-calendar               { &:before { content: \"\\e109\"; } }\n.glyphicon-random                 { &:before { content: \"\\e110\"; } }\n.glyphicon-comment                { &:before { content: \"\\e111\"; } }\n.glyphicon-magnet                 { &:before { content: \"\\e112\"; } }\n.glyphicon-chevron-up             { &:before { content: \"\\e113\"; } }\n.glyphicon-chevron-down           { &:before { content: \"\\e114\"; } }\n.glyphicon-retweet                { &:before { content: \"\\e115\"; } }\n.glyphicon-shopping-cart          { &:before { content: \"\\e116\"; } }\n.glyphicon-folder-close           { &:before { content: \"\\e117\"; } }\n.glyphicon-folder-open            { &:before { content: \"\\e118\"; } }\n.glyphicon-resize-vertical        { &:before { content: \"\\e119\"; } }\n.glyphicon-resize-horizontal      { &:before { content: \"\\e120\"; } }\n.glyphicon-hdd                    { &:before { content: \"\\e121\"; } }\n.glyphicon-bullhorn               { &:before { content: \"\\e122\"; } }\n.glyphicon-bell                   { &:before { content: \"\\e123\"; } }\n.glyphicon-certificate            { &:before { content: \"\\e124\"; } }\n.glyphicon-thumbs-up              { &:before { content: \"\\e125\"; } }\n.glyphicon-thumbs-down            { &:before { content: \"\\e126\"; } }\n.glyphicon-hand-right             { &:before { content: \"\\e127\"; } }\n.glyphicon-hand-left              { &:before { content: \"\\e128\"; } }\n.glyphicon-hand-up                { &:before { content: \"\\e129\"; } }\n.glyphicon-hand-down              { &:before { content: \"\\e130\"; } }\n.glyphicon-circle-arrow-right     { &:before { content: \"\\e131\"; } }\n.glyphicon-circle-arrow-left      { &:before { content: \"\\e132\"; } }\n.glyphicon-circle-arrow-up        { &:before { content: \"\\e133\"; } }\n.glyphicon-circle-arrow-down      { &:before { content: \"\\e134\"; } }\n.glyphicon-globe                  { &:before { content: \"\\e135\"; } }\n.glyphicon-wrench                 { &:before { content: \"\\e136\"; } }\n.glyphicon-tasks                  { &:before { content: \"\\e137\"; } }\n.glyphicon-filter                 { &:before { content: \"\\e138\"; } }\n.glyphicon-briefcase              { &:before { content: \"\\e139\"; } }\n.glyphicon-fullscreen             { &:before { content: \"\\e140\"; } }\n.glyphicon-dashboard              { &:before { content: \"\\e141\"; } }\n.glyphicon-paperclip              { &:before { content: \"\\e142\"; } }\n.glyphicon-heart-empty            { &:before { content: \"\\e143\"; } }\n.glyphicon-link                   { &:before { content: \"\\e144\"; } }\n.glyphicon-phone                  { &:before { content: \"\\e145\"; } }\n.glyphicon-pushpin                { &:before { content: \"\\e146\"; } }\n.glyphicon-usd                    { &:before { content: \"\\e148\"; } }\n.glyphicon-gbp                    { &:before { content: \"\\e149\"; } }\n.glyphicon-sort                   { &:before { content: \"\\e150\"; } }\n.glyphicon-sort-by-alphabet       { &:before { content: \"\\e151\"; } }\n.glyphicon-sort-by-alphabet-alt   { &:before { content: \"\\e152\"; } }\n.glyphicon-sort-by-order          { &:before { content: \"\\e153\"; } }\n.glyphicon-sort-by-order-alt      { &:before { content: \"\\e154\"; } }\n.glyphicon-sort-by-attributes     { &:before { content: \"\\e155\"; } }\n.glyphicon-sort-by-attributes-alt { &:before { content: \"\\e156\"; } }\n.glyphicon-unchecked              { &:before { content: \"\\e157\"; } }\n.glyphicon-expand                 { &:before { content: \"\\e158\"; } }\n.glyphicon-collapse-down          { &:before { content: \"\\e159\"; } }\n.glyphicon-collapse-up            { &:before { content: \"\\e160\"; } }\n.glyphicon-log-in                 { &:before { content: \"\\e161\"; } }\n.glyphicon-flash                  { &:before { content: \"\\e162\"; } }\n.glyphicon-log-out                { &:before { content: \"\\e163\"; } }\n.glyphicon-new-window             { &:before { content: \"\\e164\"; } }\n.glyphicon-record                 { &:before { content: \"\\e165\"; } }\n.glyphicon-save                   { &:before { content: \"\\e166\"; } }\n.glyphicon-open                   { &:before { content: \"\\e167\"; } }\n.glyphicon-saved                  { &:before { content: \"\\e168\"; } }\n.glyphicon-import                 { &:before { content: \"\\e169\"; } }\n.glyphicon-export                 { &:before { content: \"\\e170\"; } }\n.glyphicon-send                   { &:before { content: \"\\e171\"; } }\n.glyphicon-floppy-disk            { &:before { content: \"\\e172\"; } }\n.glyphicon-floppy-saved           { &:before { content: \"\\e173\"; } }\n.glyphicon-floppy-remove          { &:before { content: \"\\e174\"; } }\n.glyphicon-floppy-save            { &:before { content: \"\\e175\"; } }\n.glyphicon-floppy-open            { &:before { content: \"\\e176\"; } }\n.glyphicon-credit-card            { &:before { content: \"\\e177\"; } }\n.glyphicon-transfer               { &:before { content: \"\\e178\"; } }\n.glyphicon-cutlery                { &:before { content: \"\\e179\"; } }\n.glyphicon-header                 { &:before { content: \"\\e180\"; } }\n.glyphicon-compressed             { &:before { content: \"\\e181\"; } }\n.glyphicon-earphone               { &:before { content: \"\\e182\"; } }\n.glyphicon-phone-alt              { &:before { content: \"\\e183\"; } }\n.glyphicon-tower                  { &:before { content: \"\\e184\"; } }\n.glyphicon-stats                  { &:before { content: \"\\e185\"; } }\n.glyphicon-sd-video               { &:before { content: \"\\e186\"; } }\n.glyphicon-hd-video               { &:before { content: \"\\e187\"; } }\n.glyphicon-subtitles              { &:before { content: \"\\e188\"; } }\n.glyphicon-sound-stereo           { &:before { content: \"\\e189\"; } }\n.glyphicon-sound-dolby            { &:before { content: \"\\e190\"; } }\n.glyphicon-sound-5-1              { &:before { content: \"\\e191\"; } }\n.glyphicon-sound-6-1              { &:before { content: \"\\e192\"; } }\n.glyphicon-sound-7-1              { &:before { content: \"\\e193\"; } }\n.glyphicon-copyright-mark         { &:before { content: \"\\e194\"; } }\n.glyphicon-registration-mark      { &:before { content: \"\\e195\"; } }\n.glyphicon-cloud-download         { &:before { content: \"\\e197\"; } }\n.glyphicon-cloud-upload           { &:before { content: \"\\e198\"; } }\n.glyphicon-tree-conifer           { &:before { content: \"\\e199\"; } }\n.glyphicon-tree-deciduous         { &:before { content: \"\\e200\"; } }\n","//\n// Dropdown menus\n// --------------------------------------------------\n\n\n// Dropdown arrow/caret\n.caret {\n  display: inline-block;\n  width: 0;\n  height: 0;\n  margin-left: 2px;\n  vertical-align: middle;\n  border-top:   @caret-width-base solid;\n  border-right: @caret-width-base solid transparent;\n  border-left:  @caret-width-base solid transparent;\n}\n\n// The dropdown wrapper (div)\n.dropdown {\n  position: relative;\n}\n\n// Prevent the focus on the dropdown toggle when closing dropdowns\n.dropdown-toggle:focus {\n  outline: 0;\n}\n\n// The dropdown menu (ul)\n.dropdown-menu {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  z-index: @zindex-dropdown;\n  display: none; // none by default, but block on \"open\" of the menu\n  float: left;\n  min-width: 160px;\n  padding: 5px 0;\n  margin: 2px 0 0; // override default ul\n  list-style: none;\n  font-size: @font-size-base;\n  background-color: @dropdown-bg;\n  border: 1px solid @dropdown-fallback-border; // IE8 fallback\n  border: 1px solid @dropdown-border;\n  border-radius: @border-radius-base;\n  .box-shadow(0 6px 12px rgba(0,0,0,.175));\n  background-clip: padding-box;\n\n  // Aligns the dropdown menu to right\n  //\n  // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]`\n  &.pull-right {\n    right: 0;\n    left: auto;\n  }\n\n  // Dividers (basically an hr) within the dropdown\n  .divider {\n    .nav-divider(@dropdown-divider-bg);\n  }\n\n  // Links within the dropdown menu\n  > li > a {\n    display: block;\n    padding: 3px 20px;\n    clear: both;\n    font-weight: normal;\n    line-height: @line-height-base;\n    color: @dropdown-link-color;\n    white-space: nowrap; // prevent links from randomly breaking onto new lines\n  }\n}\n\n// Hover/Focus state\n.dropdown-menu > li > a {\n  &:hover,\n  &:focus {\n    text-decoration: none;\n    color: @dropdown-link-hover-color;\n    background-color: @dropdown-link-hover-bg;\n  }\n}\n\n// Active state\n.dropdown-menu > .active > a {\n  &,\n  &:hover,\n  &:focus {\n    color: @dropdown-link-active-color;\n    text-decoration: none;\n    outline: 0;\n    background-color: @dropdown-link-active-bg;\n  }\n}\n\n// Disabled state\n//\n// Gray out text and ensure the hover/focus state remains gray\n\n.dropdown-menu > .disabled > a {\n  &,\n  &:hover,\n  &:focus {\n    color: @dropdown-link-disabled-color;\n  }\n}\n// Nuke hover/focus effects\n.dropdown-menu > .disabled > a {\n  &:hover,\n  &:focus {\n    text-decoration: none;\n    background-color: transparent;\n    background-image: none; // Remove CSS gradient\n    .reset-filter();\n    cursor: not-allowed;\n  }\n}\n\n// Open state for the dropdown\n.open {\n  // Show the menu\n  > .dropdown-menu {\n    display: block;\n  }\n\n  // Remove the outline when :focus is triggered\n  > a {\n    outline: 0;\n  }\n}\n\n// Menu positioning\n//\n// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown\n// menu with the parent.\n.dropdown-menu-right {\n  left: auto; // Reset the default from `.dropdown-menu`\n  right: 0;\n}\n// With v3, we enabled auto-flipping if you have a dropdown within a right\n// aligned nav component. To enable the undoing of that, we provide an override\n// to restore the default dropdown menu alignment.\n//\n// This is only for left-aligning a dropdown menu within a `.navbar-right` or\n// `.pull-right` nav component.\n.dropdown-menu-left {\n  left: 0;\n  right: auto;\n}\n\n// Dropdown section headers\n.dropdown-header {\n  display: block;\n  padding: 3px 20px;\n  font-size: @font-size-small;\n  line-height: @line-height-base;\n  color: @dropdown-header-color;\n}\n\n// Backdrop to catch body clicks on mobile, etc.\n.dropdown-backdrop {\n  position: fixed;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  top: 0;\n  z-index: (@zindex-dropdown - 10);\n}\n\n// Right aligned dropdowns\n.pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n\n// Allow for dropdowns to go bottom up (aka, dropup-menu)\n//\n// Just add .dropup after the standard .dropdown class and you're set, bro.\n// TODO: abstract this so that the navbar fixed styles are not placed here?\n\n.dropup,\n.navbar-fixed-bottom .dropdown {\n  // Reverse the caret\n  .caret {\n    border-top: 0;\n    border-bottom: @caret-width-base solid;\n    content: \"\";\n  }\n  // Different positioning for bottom up menu\n  .dropdown-menu {\n    top: auto;\n    bottom: 100%;\n    margin-bottom: 1px;\n  }\n}\n\n\n// Component alignment\n//\n// Reiterate per navbar.less and the modified component alignment there.\n\n@media (min-width: @grid-float-breakpoint) {\n  .navbar-right {\n    .dropdown-menu {\n      .dropdown-menu-right();\n    }\n    // Necessary for overrides of the default right aligned menu.\n    // Will remove come v4 in all likelihood.\n    .dropdown-menu-left {\n      .dropdown-menu-left();\n    }\n  }\n}\n\n","//\n// Input groups\n// --------------------------------------------------\n\n// Base styles\n// -------------------------\n.input-group {\n  position: relative; // For dropdowns\n  display: table;\n  border-collapse: separate; // prevent input groups from inheriting border styles from table cells when placed within a table\n\n  // Undo padding and float of grid classes\n  &[class*=\"col-\"] {\n    float: none;\n    padding-left: 0;\n    padding-right: 0;\n  }\n\n  .form-control {\n    // Ensure that the input is always above the *appended* addon button for\n    // proper border colors.\n    position: relative;\n    z-index: 2;\n\n    // IE9 fubars the placeholder attribute in text inputs and the arrows on\n    // select elements in input groups. To fix it, we float the input. Details:\n    // https://github.com/twbs/bootstrap/issues/11561#issuecomment-28936855\n    float: left;\n\n    width: 100%;\n    margin-bottom: 0;\n  }\n}\n\n// Sizing options\n//\n// Remix the default form control sizing classes into new ones for easier\n// manipulation.\n\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn { .input-lg(); }\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn { .input-sm(); }\n\n\n// Display as table-cell\n// -------------------------\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n  display: table-cell;\n\n  &:not(:first-child):not(:last-child) {\n    border-radius: 0;\n  }\n}\n// Addon and addon wrapper for buttons\n.input-group-addon,\n.input-group-btn {\n  width: 1%;\n  white-space: nowrap;\n  vertical-align: middle; // Match the inputs\n}\n\n// Text input groups\n// -------------------------\n.input-group-addon {\n  padding: @padding-base-vertical @padding-base-horizontal;\n  font-size: @font-size-base;\n  font-weight: normal;\n  line-height: 1;\n  color: @input-color;\n  text-align: center;\n  background-color: @input-group-addon-bg;\n  border: 1px solid @input-group-addon-border-color;\n  border-radius: @border-radius-base;\n\n  // Sizing\n  &.input-sm {\n    padding: @padding-small-vertical @padding-small-horizontal;\n    font-size: @font-size-small;\n    border-radius: @border-radius-small;\n  }\n  &.input-lg {\n    padding: @padding-large-vertical @padding-large-horizontal;\n    font-size: @font-size-large;\n    border-radius: @border-radius-large;\n  }\n\n  // Nuke default margins from checkboxes and radios to vertically center within.\n  input[type=\"radio\"],\n  input[type=\"checkbox\"] {\n    margin-top: 0;\n  }\n}\n\n// Reset rounded corners\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n  .border-right-radius(0);\n}\n.input-group-addon:first-child {\n  border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n  .border-left-radius(0);\n}\n.input-group-addon:last-child {\n  border-left: 0;\n}\n\n// Button input groups\n// -------------------------\n.input-group-btn {\n  position: relative;\n  // Jankily prevent input button groups from wrapping with `white-space` and\n  // `font-size` in combination with `inline-block` on buttons.\n  font-size: 0;\n  white-space: nowrap;\n\n  // Negative margin for spacing, position for bringing hovered/focused/actived\n  // element above the siblings.\n  > .btn {\n    position: relative;\n    + .btn {\n      margin-left: -1px;\n    }\n    // Bring the \"active\" button to the front\n    &:hover,\n    &:focus,\n    &:active {\n      z-index: 2;\n    }\n  }\n\n  // Negative margin to only have a 1px border between the two\n  &:first-child {\n    > .btn,\n    > .btn-group {\n      margin-right: -1px;\n    }\n  }\n  &:last-child {\n    > .btn,\n    > .btn-group {\n      margin-left: -1px;\n    }\n  }\n}\n","//\n// Navs\n// --------------------------------------------------\n\n\n// Base class\n// --------------------------------------------------\n\n.nav {\n  margin-bottom: 0;\n  padding-left: 0; // Override default ul/ol\n  list-style: none;\n  &:extend(.clearfix all);\n\n  > li {\n    position: relative;\n    display: block;\n\n    > a {\n      position: relative;\n      display: block;\n      padding: @nav-link-padding;\n      &:hover,\n      &:focus {\n        text-decoration: none;\n        background-color: @nav-link-hover-bg;\n      }\n    }\n\n    // Disabled state sets text to gray and nukes hover/tab effects\n    &.disabled > a {\n      color: @nav-disabled-link-color;\n\n      &:hover,\n      &:focus {\n        color: @nav-disabled-link-hover-color;\n        text-decoration: none;\n        background-color: transparent;\n        cursor: not-allowed;\n      }\n    }\n  }\n\n  // Open dropdowns\n  .open > a {\n    &,\n    &:hover,\n    &:focus {\n      background-color: @nav-link-hover-bg;\n      border-color: @link-color;\n    }\n  }\n\n  // Nav dividers (deprecated with v3.0.1)\n  //\n  // This should have been removed in v3 with the dropping of `.nav-list`, but\n  // we missed it. We don't currently support this anywhere, but in the interest\n  // of maintaining backward compatibility in case you use it, it's deprecated.\n  .nav-divider {\n    .nav-divider();\n  }\n\n  // Prevent IE8 from misplacing imgs\n  //\n  // See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989\n  > li > a > img {\n    max-width: none;\n  }\n}\n\n\n// Tabs\n// -------------------------\n\n// Give the tabs something to sit on\n.nav-tabs {\n  border-bottom: 1px solid @nav-tabs-border-color;\n  > li {\n    float: left;\n    // Make the list-items overlay the bottom border\n    margin-bottom: -1px;\n\n    // Actual tabs (as links)\n    > a {\n      margin-right: 2px;\n      line-height: @line-height-base;\n      border: 1px solid transparent;\n      border-radius: @border-radius-base @border-radius-base 0 0;\n      &:hover {\n        border-color: @nav-tabs-link-hover-border-color @nav-tabs-link-hover-border-color @nav-tabs-border-color;\n      }\n    }\n\n    // Active state, and its :hover to override normal :hover\n    &.active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @nav-tabs-active-link-hover-color;\n        background-color: @nav-tabs-active-link-hover-bg;\n        border: 1px solid @nav-tabs-active-link-hover-border-color;\n        border-bottom-color: transparent;\n        cursor: default;\n      }\n    }\n  }\n  // pulling this in mainly for less shorthand\n  &.nav-justified {\n    .nav-justified();\n    .nav-tabs-justified();\n  }\n}\n\n\n// Pills\n// -------------------------\n.nav-pills {\n  > li {\n    float: left;\n\n    // Links rendered as pills\n    > a {\n      border-radius: @nav-pills-border-radius;\n    }\n    + li {\n      margin-left: 2px;\n    }\n\n    // Active state\n    &.active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @nav-pills-active-link-hover-color;\n        background-color: @nav-pills-active-link-hover-bg;\n      }\n    }\n  }\n}\n\n\n// Stacked pills\n.nav-stacked {\n  > li {\n    float: none;\n    + li {\n      margin-top: 2px;\n      margin-left: 0; // no need for this gap between nav items\n    }\n  }\n}\n\n\n// Nav variations\n// --------------------------------------------------\n\n// Justified nav links\n// -------------------------\n\n.nav-justified {\n  width: 100%;\n\n  > li {\n    float: none;\n     > a {\n      text-align: center;\n      margin-bottom: 5px;\n    }\n  }\n\n  > .dropdown .dropdown-menu {\n    top: auto;\n    left: auto;\n  }\n\n  @media (min-width: @screen-sm-min) {\n    > li {\n      display: table-cell;\n      width: 1%;\n      > a {\n        margin-bottom: 0;\n      }\n    }\n  }\n}\n\n// Move borders to anchors instead of bottom of list\n//\n// Mixin for adding on top the shared `.nav-justified` styles for our tabs\n.nav-tabs-justified {\n  border-bottom: 0;\n\n  > li > a {\n    // Override margin from .nav-tabs\n    margin-right: 0;\n    border-radius: @border-radius-base;\n  }\n\n  > .active > a,\n  > .active > a:hover,\n  > .active > a:focus {\n    border: 1px solid @nav-tabs-justified-link-border-color;\n  }\n\n  @media (min-width: @screen-sm-min) {\n    > li > a {\n      border-bottom: 1px solid @nav-tabs-justified-link-border-color;\n      border-radius: @border-radius-base @border-radius-base 0 0;\n    }\n    > .active > a,\n    > .active > a:hover,\n    > .active > a:focus {\n      border-bottom-color: @nav-tabs-justified-active-link-border-color;\n    }\n  }\n}\n\n\n// Tabbable tabs\n// -------------------------\n\n// Hide tabbable panes to start, show them when `.active`\n.tab-content {\n  > .tab-pane {\n    display: none;\n  }\n  > .active {\n    display: block;\n  }\n}\n\n\n// Dropdowns\n// -------------------------\n\n// Specific dropdowns\n.nav-tabs .dropdown-menu {\n  // make dropdown border overlap tab border\n  margin-top: -1px;\n  // Remove the top rounded corners here since there is a hard edge above the menu\n  .border-top-radius(0);\n}\n","//\n// Navbars\n// --------------------------------------------------\n\n\n// Wrapper and base class\n//\n// Provide a static navbar from which we expand to create full-width, fixed, and\n// other navbar variations.\n\n.navbar {\n  position: relative;\n  min-height: @navbar-height; // Ensure a navbar always shows (e.g., without a .navbar-brand in collapsed mode)\n  margin-bottom: @navbar-margin-bottom;\n  border: 1px solid transparent;\n\n  // Prevent floats from breaking the navbar\n  &:extend(.clearfix all);\n\n  @media (min-width: @grid-float-breakpoint) {\n    border-radius: @navbar-border-radius;\n  }\n}\n\n\n// Navbar heading\n//\n// Groups `.navbar-brand` and `.navbar-toggle` into a single component for easy\n// styling of responsive aspects.\n\n.navbar-header {\n  &:extend(.clearfix all);\n\n  @media (min-width: @grid-float-breakpoint) {\n    float: left;\n  }\n}\n\n\n// Navbar collapse (body)\n//\n// Group your navbar content into this for easy collapsing and expanding across\n// various device sizes. By default, this content is collapsed when <768px, but\n// will expand past that for a horizontal display.\n//\n// To start (on mobile devices) the navbar links, forms, and buttons are stacked\n// vertically and include a `max-height` to overflow in case you have too much\n// content for the user's viewport.\n\n.navbar-collapse {\n  max-height: @navbar-collapse-max-height;\n  overflow-x: visible;\n  padding-right: @navbar-padding-horizontal;\n  padding-left:  @navbar-padding-horizontal;\n  border-top: 1px solid transparent;\n  box-shadow: inset 0 1px 0 rgba(255,255,255,.1);\n  &:extend(.clearfix all);\n  -webkit-overflow-scrolling: touch;\n\n  &.in {\n    overflow-y: auto;\n  }\n\n  @media (min-width: @grid-float-breakpoint) {\n    width: auto;\n    border-top: 0;\n    box-shadow: none;\n\n    &.collapse {\n      display: block !important;\n      height: auto !important;\n      padding-bottom: 0; // Override default setting\n      overflow: visible !important;\n    }\n\n    &.in {\n      overflow-y: visible;\n    }\n\n    // Undo the collapse side padding for navbars with containers to ensure\n    // alignment of right-aligned contents.\n    .navbar-fixed-top &,\n    .navbar-static-top &,\n    .navbar-fixed-bottom & {\n      padding-left: 0;\n      padding-right: 0;\n    }\n  }\n}\n\n\n// Both navbar header and collapse\n//\n// When a container is present, change the behavior of the header and collapse.\n\n.container,\n.container-fluid {\n  > .navbar-header,\n  > .navbar-collapse {\n    margin-right: -@navbar-padding-horizontal;\n    margin-left:  -@navbar-padding-horizontal;\n\n    @media (min-width: @grid-float-breakpoint) {\n      margin-right: 0;\n      margin-left:  0;\n    }\n  }\n}\n\n\n//\n// Navbar alignment options\n//\n// Display the navbar across the entirety of the page or fixed it to the top or\n// bottom of the page.\n\n// Static top (unfixed, but 100% wide) navbar\n.navbar-static-top {\n  z-index: @zindex-navbar;\n  border-width: 0 0 1px;\n\n  @media (min-width: @grid-float-breakpoint) {\n    border-radius: 0;\n  }\n}\n\n// Fix the top/bottom navbars when screen real estate supports it\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  position: fixed;\n  right: 0;\n  left: 0;\n  z-index: @zindex-navbar-fixed;\n\n  // Undo the rounded corners\n  @media (min-width: @grid-float-breakpoint) {\n    border-radius: 0;\n  }\n}\n.navbar-fixed-top {\n  top: 0;\n  border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n  bottom: 0;\n  margin-bottom: 0; // override .navbar defaults\n  border-width: 1px 0 0;\n}\n\n\n// Brand/project name\n\n.navbar-brand {\n  float: left;\n  padding: @navbar-padding-vertical @navbar-padding-horizontal;\n  font-size: @font-size-large;\n  line-height: @line-height-computed;\n  height: @navbar-height;\n\n  &:hover,\n  &:focus {\n    text-decoration: none;\n  }\n\n  @media (min-width: @grid-float-breakpoint) {\n    .navbar > .container &,\n    .navbar > .container-fluid & {\n      margin-left: -@navbar-padding-horizontal;\n    }\n  }\n}\n\n\n// Navbar toggle\n//\n// Custom button for toggling the `.navbar-collapse`, powered by the collapse\n// JavaScript plugin.\n\n.navbar-toggle {\n  position: relative;\n  float: right;\n  margin-right: @navbar-padding-horizontal;\n  padding: 9px 10px;\n  .navbar-vertical-align(34px);\n  background-color: transparent;\n  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n  border: 1px solid transparent;\n  border-radius: @border-radius-base;\n\n  // We remove the `outline` here, but later compensate by attaching `:hover`\n  // styles to `:focus`.\n  &:focus {\n    outline: none;\n  }\n\n  // Bars\n  .icon-bar {\n    display: block;\n    width: 22px;\n    height: 2px;\n    border-radius: 1px;\n  }\n  .icon-bar + .icon-bar {\n    margin-top: 4px;\n  }\n\n  @media (min-width: @grid-float-breakpoint) {\n    display: none;\n  }\n}\n\n\n// Navbar nav links\n//\n// Builds on top of the `.nav` components with its own modifier class to make\n// the nav the full height of the horizontal nav (above 768px).\n\n.navbar-nav {\n  margin: (@navbar-padding-vertical / 2) -@navbar-padding-horizontal;\n\n  > li > a {\n    padding-top:    10px;\n    padding-bottom: 10px;\n    line-height: @line-height-computed;\n  }\n\n  @media (max-width: @grid-float-breakpoint-max) {\n    // Dropdowns get custom display when collapsed\n    .open .dropdown-menu {\n      position: static;\n      float: none;\n      width: auto;\n      margin-top: 0;\n      background-color: transparent;\n      border: 0;\n      box-shadow: none;\n      > li > a,\n      .dropdown-header {\n        padding: 5px 15px 5px 25px;\n      }\n      > li > a {\n        line-height: @line-height-computed;\n        &:hover,\n        &:focus {\n          background-image: none;\n        }\n      }\n    }\n  }\n\n  // Uncollapse the nav\n  @media (min-width: @grid-float-breakpoint) {\n    float: left;\n    margin: 0;\n\n    > li {\n      float: left;\n      > a {\n        padding-top:    @navbar-padding-vertical;\n        padding-bottom: @navbar-padding-vertical;\n      }\n    }\n\n    &.navbar-right:last-child {\n      margin-right: -@navbar-padding-horizontal;\n    }\n  }\n}\n\n\n// Component alignment\n//\n// Repurpose the pull utilities as their own navbar utilities to avoid specificity\n// issues with parents and chaining. Only do this when the navbar is uncollapsed\n// though so that navbar contents properly stack and align in mobile.\n\n@media (min-width: @grid-float-breakpoint) {\n  .navbar-left  { .pull-left(); }\n  .navbar-right { .pull-right(); }\n}\n\n\n// Navbar form\n//\n// Extension of the `.form-inline` with some extra flavor for optimum display in\n// our navbars.\n\n.navbar-form {\n  margin-left: -@navbar-padding-horizontal;\n  margin-right: -@navbar-padding-horizontal;\n  padding: 10px @navbar-padding-horizontal;\n  border-top: 1px solid transparent;\n  border-bottom: 1px solid transparent;\n  @shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);\n  .box-shadow(@shadow);\n\n  // Mixin behavior for optimum display\n  .form-inline();\n\n  .form-group {\n    @media (max-width: @grid-float-breakpoint-max) {\n      margin-bottom: 5px;\n    }\n  }\n\n  // Vertically center in expanded, horizontal navbar\n  .navbar-vertical-align(@input-height-base);\n\n  // Undo 100% width for pull classes\n  @media (min-width: @grid-float-breakpoint) {\n    width: auto;\n    border: 0;\n    margin-left: 0;\n    margin-right: 0;\n    padding-top: 0;\n    padding-bottom: 0;\n    .box-shadow(none);\n\n    // Outdent the form if last child to line up with content down the page\n    &.navbar-right:last-child {\n      margin-right: -@navbar-padding-horizontal;\n    }\n  }\n}\n\n\n// Dropdown menus\n\n// Menu position and menu carets\n.navbar-nav > li > .dropdown-menu {\n  margin-top: 0;\n  .border-top-radius(0);\n}\n// Menu position and menu caret support for dropups via extra dropup class\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n  .border-bottom-radius(0);\n}\n\n\n// Buttons in navbars\n//\n// Vertically center a button within a navbar (when *not* in a form).\n\n.navbar-btn {\n  .navbar-vertical-align(@input-height-base);\n\n  &.btn-sm {\n    .navbar-vertical-align(@input-height-small);\n  }\n  &.btn-xs {\n    .navbar-vertical-align(22);\n  }\n}\n\n\n// Text in navbars\n//\n// Add a class to make any element properly align itself vertically within the navbars.\n\n.navbar-text {\n  .navbar-vertical-align(@line-height-computed);\n\n  @media (min-width: @grid-float-breakpoint) {\n    float: left;\n    margin-left: @navbar-padding-horizontal;\n    margin-right: @navbar-padding-horizontal;\n\n    // Outdent the form if last child to line up with content down the page\n    &.navbar-right:last-child {\n      margin-right: 0;\n    }\n  }\n}\n\n// Alternate navbars\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n  background-color: @navbar-default-bg;\n  border-color: @navbar-default-border;\n\n  .navbar-brand {\n    color: @navbar-default-brand-color;\n    &:hover,\n    &:focus {\n      color: @navbar-default-brand-hover-color;\n      background-color: @navbar-default-brand-hover-bg;\n    }\n  }\n\n  .navbar-text {\n    color: @navbar-default-color;\n  }\n\n  .navbar-nav {\n    > li > a {\n      color: @navbar-default-link-color;\n\n      &:hover,\n      &:focus {\n        color: @navbar-default-link-hover-color;\n        background-color: @navbar-default-link-hover-bg;\n      }\n    }\n    > .active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-default-link-active-color;\n        background-color: @navbar-default-link-active-bg;\n      }\n    }\n    > .disabled > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-default-link-disabled-color;\n        background-color: @navbar-default-link-disabled-bg;\n      }\n    }\n  }\n\n  .navbar-toggle {\n    border-color: @navbar-default-toggle-border-color;\n    &:hover,\n    &:focus {\n      background-color: @navbar-default-toggle-hover-bg;\n    }\n    .icon-bar {\n      background-color: @navbar-default-toggle-icon-bar-bg;\n    }\n  }\n\n  .navbar-collapse,\n  .navbar-form {\n    border-color: @navbar-default-border;\n  }\n\n  // Dropdown menu items\n  .navbar-nav {\n    // Remove background color from open dropdown\n    > .open > a {\n      &,\n      &:hover,\n      &:focus {\n        background-color: @navbar-default-link-active-bg;\n        color: @navbar-default-link-active-color;\n      }\n    }\n\n    @media (max-width: @grid-float-breakpoint-max) {\n      // Dropdowns get custom display when collapsed\n      .open .dropdown-menu {\n        > li > a {\n          color: @navbar-default-link-color;\n          &:hover,\n          &:focus {\n            color: @navbar-default-link-hover-color;\n            background-color: @navbar-default-link-hover-bg;\n          }\n        }\n        > .active > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-default-link-active-color;\n            background-color: @navbar-default-link-active-bg;\n          }\n        }\n        > .disabled > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-default-link-disabled-color;\n            background-color: @navbar-default-link-disabled-bg;\n          }\n        }\n      }\n    }\n  }\n\n\n  // Links in navbars\n  //\n  // Add a class to ensure links outside the navbar nav are colored correctly.\n\n  .navbar-link {\n    color: @navbar-default-link-color;\n    &:hover {\n      color: @navbar-default-link-hover-color;\n    }\n  }\n\n}\n\n// Inverse navbar\n\n.navbar-inverse {\n  background-color: @navbar-inverse-bg;\n  border-color: @navbar-inverse-border;\n\n  .navbar-brand {\n    color: @navbar-inverse-brand-color;\n    &:hover,\n    &:focus {\n      color: @navbar-inverse-brand-hover-color;\n      background-color: @navbar-inverse-brand-hover-bg;\n    }\n  }\n\n  .navbar-text {\n    color: @navbar-inverse-color;\n  }\n\n  .navbar-nav {\n    > li > a {\n      color: @navbar-inverse-link-color;\n\n      &:hover,\n      &:focus {\n        color: @navbar-inverse-link-hover-color;\n        background-color: @navbar-inverse-link-hover-bg;\n      }\n    }\n    > .active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-inverse-link-active-color;\n        background-color: @navbar-inverse-link-active-bg;\n      }\n    }\n    > .disabled > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-inverse-link-disabled-color;\n        background-color: @navbar-inverse-link-disabled-bg;\n      }\n    }\n  }\n\n  // Darken the responsive nav toggle\n  .navbar-toggle {\n    border-color: @navbar-inverse-toggle-border-color;\n    &:hover,\n    &:focus {\n      background-color: @navbar-inverse-toggle-hover-bg;\n    }\n    .icon-bar {\n      background-color: @navbar-inverse-toggle-icon-bar-bg;\n    }\n  }\n\n  .navbar-collapse,\n  .navbar-form {\n    border-color: darken(@navbar-inverse-bg, 7%);\n  }\n\n  // Dropdowns\n  .navbar-nav {\n    > .open > a {\n      &,\n      &:hover,\n      &:focus {\n        background-color: @navbar-inverse-link-active-bg;\n        color: @navbar-inverse-link-active-color;\n      }\n    }\n\n    @media (max-width: @grid-float-breakpoint-max) {\n      // Dropdowns get custom display\n      .open .dropdown-menu {\n        > .dropdown-header {\n          border-color: @navbar-inverse-border;\n        }\n        .divider {\n          background-color: @navbar-inverse-border;\n        }\n        > li > a {\n          color: @navbar-inverse-link-color;\n          &:hover,\n          &:focus {\n            color: @navbar-inverse-link-hover-color;\n            background-color: @navbar-inverse-link-hover-bg;\n          }\n        }\n        > .active > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-inverse-link-active-color;\n            background-color: @navbar-inverse-link-active-bg;\n          }\n        }\n        > .disabled > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-inverse-link-disabled-color;\n            background-color: @navbar-inverse-link-disabled-bg;\n          }\n        }\n      }\n    }\n  }\n\n  .navbar-link {\n    color: @navbar-inverse-link-color;\n    &:hover {\n      color: @navbar-inverse-link-hover-color;\n    }\n  }\n\n}\n","//\n// Utility classes\n// --------------------------------------------------\n\n\n// Floats\n// -------------------------\n\n.clearfix {\n  .clearfix();\n}\n.center-block {\n  .center-block();\n}\n.pull-right {\n  float: right !important;\n}\n.pull-left {\n  float: left !important;\n}\n\n\n// Toggling content\n// -------------------------\n\n// Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1\n.hide {\n  display: none !important;\n}\n.show {\n  display: block !important;\n}\n.invisible {\n  visibility: hidden;\n}\n.text-hide {\n  .text-hide();\n}\n\n\n// Hide from screenreaders and browsers\n//\n// Credit: HTML5 Boilerplate\n\n.hidden {\n  display: none !important;\n  visibility: hidden !important;\n}\n\n\n// For Affix plugin\n// -------------------------\n\n.affix {\n  position: fixed;\n}\n","//\n// Breadcrumbs\n// --------------------------------------------------\n\n\n.breadcrumb {\n  padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal;\n  margin-bottom: @line-height-computed;\n  list-style: none;\n  background-color: @breadcrumb-bg;\n  border-radius: @border-radius-base;\n\n  > li {\n    display: inline-block;\n\n    + li:before {\n      content: \"@{breadcrumb-separator}\\00a0\"; // Unicode space added since inline-block means non-collapsing white-space\n      padding: 0 5px;\n      color: @breadcrumb-color;\n    }\n  }\n\n  > .active {\n    color: @breadcrumb-active-color;\n  }\n}\n","//\n// Pagination (multiple pages)\n// --------------------------------------------------\n.pagination {\n  display: inline-block;\n  padding-left: 0;\n  margin: @line-height-computed 0;\n  border-radius: @border-radius-base;\n\n  > li {\n    display: inline; // Remove list-style and block-level defaults\n    > a,\n    > span {\n      position: relative;\n      float: left; // Collapse white-space\n      padding: @padding-base-vertical @padding-base-horizontal;\n      line-height: @line-height-base;\n      text-decoration: none;\n      color: @pagination-color;\n      background-color: @pagination-bg;\n      border: 1px solid @pagination-border;\n      margin-left: -1px;\n    }\n    &:first-child {\n      > a,\n      > span {\n        margin-left: 0;\n        .border-left-radius(@border-radius-base);\n      }\n    }\n    &:last-child {\n      > a,\n      > span {\n        .border-right-radius(@border-radius-base);\n      }\n    }\n  }\n\n  > li > a,\n  > li > span {\n    &:hover,\n    &:focus {\n      color: @pagination-hover-color;\n      background-color: @pagination-hover-bg;\n      border-color: @pagination-hover-border;\n    }\n  }\n\n  > .active > a,\n  > .active > span {\n    &,\n    &:hover,\n    &:focus {\n      z-index: 2;\n      color: @pagination-active-color;\n      background-color: @pagination-active-bg;\n      border-color: @pagination-active-border;\n      cursor: default;\n    }\n  }\n\n  > .disabled {\n    > span,\n    > span:hover,\n    > span:focus,\n    > a,\n    > a:hover,\n    > a:focus {\n      color: @pagination-disabled-color;\n      background-color: @pagination-disabled-bg;\n      border-color: @pagination-disabled-border;\n      cursor: not-allowed;\n    }\n  }\n}\n\n// Sizing\n// --------------------------------------------------\n\n// Large\n.pagination-lg {\n  .pagination-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @border-radius-large);\n}\n\n// Small\n.pagination-sm {\n  .pagination-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @border-radius-small);\n}\n","//\n// Pager pagination\n// --------------------------------------------------\n\n\n.pager {\n  padding-left: 0;\n  margin: @line-height-computed 0;\n  list-style: none;\n  text-align: center;\n  &:extend(.clearfix all);\n  li {\n    display: inline;\n    > a,\n    > span {\n      display: inline-block;\n      padding: 5px 14px;\n      background-color: @pager-bg;\n      border: 1px solid @pager-border;\n      border-radius: @pager-border-radius;\n    }\n\n    > a:hover,\n    > a:focus {\n      text-decoration: none;\n      background-color: @pager-hover-bg;\n    }\n  }\n\n  .next {\n    > a,\n    > span {\n      float: right;\n    }\n  }\n\n  .previous {\n    > a,\n    > span {\n      float: left;\n    }\n  }\n\n  .disabled {\n    > a,\n    > a:hover,\n    > a:focus,\n    > span {\n      color: @pager-disabled-color;\n      background-color: @pager-bg;\n      cursor: not-allowed;\n    }\n  }\n\n}\n","//\n// Labels\n// --------------------------------------------------\n\n.label {\n  display: inline;\n  padding: .2em .6em .3em;\n  font-size: 75%;\n  font-weight: bold;\n  line-height: 1;\n  color: @label-color;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: baseline;\n  border-radius: .25em;\n\n  // Add hover effects, but only for links\n  &[href] {\n    &:hover,\n    &:focus {\n      color: @label-link-hover-color;\n      text-decoration: none;\n      cursor: pointer;\n    }\n  }\n\n  // Empty labels collapse automatically (not available in IE8)\n  &:empty {\n    display: none;\n  }\n\n  // Quick fix for labels in buttons\n  .btn & {\n    position: relative;\n    top: -1px;\n  }\n}\n\n// Colors\n// Contextual variations (linked labels get darker on :hover)\n\n.label-default {\n  .label-variant(@label-default-bg);\n}\n\n.label-primary {\n  .label-variant(@label-primary-bg);\n}\n\n.label-success {\n  .label-variant(@label-success-bg);\n}\n\n.label-info {\n  .label-variant(@label-info-bg);\n}\n\n.label-warning {\n  .label-variant(@label-warning-bg);\n}\n\n.label-danger {\n  .label-variant(@label-danger-bg);\n}\n","//\n// Badges\n// --------------------------------------------------\n\n\n// Base classes\n.badge {\n  display: inline-block;\n  min-width: 10px;\n  padding: 3px 7px;\n  font-size: @font-size-small;\n  font-weight: @badge-font-weight;\n  color: @badge-color;\n  line-height: @badge-line-height;\n  vertical-align: baseline;\n  white-space: nowrap;\n  text-align: center;\n  background-color: @badge-bg;\n  border-radius: @badge-border-radius;\n\n  // Empty badges collapse automatically (not available in IE8)\n  &:empty {\n    display: none;\n  }\n\n  // Quick fix for badges in buttons\n  .btn & {\n    position: relative;\n    top: -1px;\n  }\n  .btn-xs & {\n    top: 0;\n    padding: 1px 5px;\n  }\n}\n\n// Hover state, but only for links\na.badge {\n  &:hover,\n  &:focus {\n    color: @badge-link-hover-color;\n    text-decoration: none;\n    cursor: pointer;\n  }\n}\n\n// Account for counters in navs\na.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n  color: @badge-active-color;\n  background-color: @badge-active-bg;\n}\n.nav-pills > li > a > .badge {\n  margin-left: 3px;\n}\n","//\n// Jumbotron\n// --------------------------------------------------\n\n\n.jumbotron {\n  padding: @jumbotron-padding;\n  margin-bottom: @jumbotron-padding;\n  color: @jumbotron-color;\n  background-color: @jumbotron-bg;\n\n  h1,\n  .h1 {\n    color: @jumbotron-heading-color;\n  }\n  p {\n    margin-bottom: (@jumbotron-padding / 2);\n    font-size: @jumbotron-font-size;\n    font-weight: 200;\n  }\n\n  .container & {\n    border-radius: @border-radius-large; // Only round corners at higher resolutions if contained in a container\n  }\n\n  .container {\n    max-width: 100%;\n  }\n\n  @media screen and (min-width: @screen-sm-min) {\n    padding-top:    (@jumbotron-padding * 1.6);\n    padding-bottom: (@jumbotron-padding * 1.6);\n\n    .container & {\n      padding-left:  (@jumbotron-padding * 2);\n      padding-right: (@jumbotron-padding * 2);\n    }\n\n    h1,\n    .h1 {\n      font-size: (@font-size-base * 4.5);\n    }\n  }\n}\n","//\n// Alerts\n// --------------------------------------------------\n\n\n// Base styles\n// -------------------------\n\n.alert {\n  padding: @alert-padding;\n  margin-bottom: @line-height-computed;\n  border: 1px solid transparent;\n  border-radius: @alert-border-radius;\n\n  // Headings for larger alerts\n  h4 {\n    margin-top: 0;\n    // Specified for the h4 to prevent conflicts of changing @headings-color\n    color: inherit;\n  }\n  // Provide class for links that match alerts\n  .alert-link {\n    font-weight: @alert-link-font-weight;\n  }\n\n  // Improve alignment and spacing of inner content\n  > p,\n  > ul {\n    margin-bottom: 0;\n  }\n  > p + p {\n    margin-top: 5px;\n  }\n}\n\n// Dismissable alerts\n//\n// Expand the right padding and account for the close button's positioning.\n\n.alert-dismissable {\n padding-right: (@alert-padding + 20);\n\n  // Adjust close link position\n  .close {\n    position: relative;\n    top: -2px;\n    right: -21px;\n    color: inherit;\n  }\n}\n\n// Alternate styles\n//\n// Generate contextual modifier classes for colorizing the alert.\n\n.alert-success {\n  .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text);\n}\n.alert-info {\n  .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text);\n}\n.alert-warning {\n  .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);\n}\n.alert-danger {\n  .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);\n}\n","//\n// Progress bars\n// --------------------------------------------------\n\n\n// Bar animations\n// -------------------------\n\n// WebKit\n@-webkit-keyframes progress-bar-stripes {\n  from  { background-position: 40px 0; }\n  to    { background-position: 0 0; }\n}\n\n// Spec and IE10+\n@keyframes progress-bar-stripes {\n  from  { background-position: 40px 0; }\n  to    { background-position: 0 0; }\n}\n\n\n\n// Bar itself\n// -------------------------\n\n// Outer container\n.progress {\n  overflow: hidden;\n  height: @line-height-computed;\n  margin-bottom: @line-height-computed;\n  background-color: @progress-bg;\n  border-radius: @border-radius-base;\n  .box-shadow(inset 0 1px 2px rgba(0,0,0,.1));\n}\n\n// Bar of progress\n.progress-bar {\n  float: left;\n  width: 0%;\n  height: 100%;\n  font-size: @font-size-small;\n  line-height: @line-height-computed;\n  color: @progress-bar-color;\n  text-align: center;\n  background-color: @progress-bar-bg;\n  .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));\n  .transition(width .6s ease);\n}\n\n// Striped bars\n.progress-striped .progress-bar {\n  #gradient > .striped();\n  background-size: 40px 40px;\n}\n\n// Call animation for the active one\n.progress.active .progress-bar {\n  .animation(progress-bar-stripes 2s linear infinite);\n}\n\n\n\n// Variations\n// -------------------------\n\n.progress-bar-success {\n  .progress-bar-variant(@progress-bar-success-bg);\n}\n\n.progress-bar-info {\n  .progress-bar-variant(@progress-bar-info-bg);\n}\n\n.progress-bar-warning {\n  .progress-bar-variant(@progress-bar-warning-bg);\n}\n\n.progress-bar-danger {\n  .progress-bar-variant(@progress-bar-danger-bg);\n}\n","// Media objects\n// Source: http://stubbornella.org/content/?p=497\n// --------------------------------------------------\n\n\n// Common styles\n// -------------------------\n\n// Clear the floats\n.media,\n.media-body {\n  overflow: hidden;\n  zoom: 1;\n}\n\n// Proper spacing between instances of .media\n.media,\n.media .media {\n  margin-top: 15px;\n}\n.media:first-child {\n  margin-top: 0;\n}\n\n// For images and videos, set to block\n.media-object {\n  display: block;\n}\n\n// Reset margins on headings for tighter default spacing\n.media-heading {\n  margin: 0 0 5px;\n}\n\n\n// Media image alignment\n// -------------------------\n\n.media {\n  > .pull-left {\n    margin-right: 10px;\n  }\n  > .pull-right {\n    margin-left: 10px;\n  }\n}\n\n\n// Media list variation\n// -------------------------\n\n// Undo default ul/ol styles\n.media-list {\n  padding-left: 0;\n  list-style: none;\n}\n","//\n// List groups\n// --------------------------------------------------\n\n\n// Base class\n//\n// Easily usable on 
      ,
        , or
        .\n\n.list-group {\n // No need to set list-style: none; since .list-group-item is block level\n margin-bottom: 20px;\n padding-left: 0; // reset padding because ul and ol\n}\n\n\n// Individual list items\n//\n// Use on `li`s or `div`s within the `.list-group` parent.\n\n.list-group-item {\n position: relative;\n display: block;\n padding: 10px 15px;\n // Place the border on the list items and negative margin up for better styling\n margin-bottom: -1px;\n background-color: @list-group-bg;\n border: 1px solid @list-group-border;\n\n // Round the first and last items\n &:first-child {\n .border-top-radius(@list-group-border-radius);\n }\n &:last-child {\n margin-bottom: 0;\n .border-bottom-radius(@list-group-border-radius);\n }\n\n // Align badges within list items\n > .badge {\n float: right;\n }\n > .badge + .badge {\n margin-right: 5px;\n }\n}\n\n\n// Linked list items\n//\n// Use anchor elements instead of `li`s or `div`s to create linked list items.\n// Includes an extra `.active` modifier class for showing selected items.\n\na.list-group-item {\n color: @list-group-link-color;\n\n .list-group-item-heading {\n color: @list-group-link-heading-color;\n }\n\n // Hover state\n &:hover,\n &:focus {\n text-decoration: none;\n background-color: @list-group-hover-bg;\n }\n\n // Active class on item itself, not parent\n &.active,\n &.active:hover,\n &.active:focus {\n z-index: 2; // Place active items above their siblings for proper border styling\n color: @list-group-active-color;\n background-color: @list-group-active-bg;\n border-color: @list-group-active-border;\n\n // Force color to inherit for custom content\n .list-group-item-heading {\n color: inherit;\n }\n .list-group-item-text {\n color: @list-group-active-text-color;\n }\n }\n}\n\n\n// Contextual variants\n//\n// Add modifier classes to change text and background color on individual items.\n// Organizationally, this must come after the `:hover` states.\n\n.list-group-item-variant(success; @state-success-bg; @state-success-text);\n.list-group-item-variant(info; @state-info-bg; @state-info-text);\n.list-group-item-variant(warning; @state-warning-bg; @state-warning-text);\n.list-group-item-variant(danger; @state-danger-bg; @state-danger-text);\n\n\n// Custom content options\n//\n// Extra classes for creating well-formatted content within `.list-group-item`s.\n\n.list-group-item-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.list-group-item-text {\n margin-bottom: 0;\n line-height: 1.3;\n}\n","//\n// Panels\n// --------------------------------------------------\n\n\n// Base class\n.panel {\n margin-bottom: @line-height-computed;\n background-color: @panel-bg;\n border: 1px solid transparent;\n border-radius: @panel-border-radius;\n .box-shadow(0 1px 1px rgba(0,0,0,.05));\n}\n\n// Panel contents\n.panel-body {\n padding: @panel-body-padding;\n &:extend(.clearfix all);\n}\n\n// Optional heading\n.panel-heading {\n padding: 10px 15px;\n border-bottom: 1px solid transparent;\n .border-top-radius((@panel-border-radius - 1));\n\n > .dropdown .dropdown-toggle {\n color: inherit;\n }\n}\n\n// Within heading, strip any `h*` tag of its default margins for spacing.\n.panel-title {\n margin-top: 0;\n margin-bottom: 0;\n font-size: ceil((@font-size-base * 1.125));\n color: inherit;\n\n > a {\n color: inherit;\n }\n}\n\n// Optional footer (stays gray in every modifier class)\n.panel-footer {\n padding: 10px 15px;\n background-color: @panel-footer-bg;\n border-top: 1px solid @panel-inner-border;\n .border-bottom-radius((@panel-border-radius - 1));\n}\n\n\n// List groups in panels\n//\n// By default, space out list group content from panel headings to account for\n// any kind of custom content between the two.\n\n.panel {\n > .list-group {\n margin-bottom: 0;\n\n .list-group-item {\n border-width: 1px 0;\n border-radius: 0;\n }\n\n // Add border top radius for first one\n &:first-child {\n .list-group-item:first-child {\n border-top: 0;\n .border-top-radius((@panel-border-radius - 1));\n }\n }\n // Add border bottom radius for last one\n &:last-child {\n .list-group-item:last-child {\n border-bottom: 0;\n .border-bottom-radius((@panel-border-radius - 1));\n }\n }\n }\n}\n// Collapse space between when there's no additional content.\n.panel-heading + .list-group {\n .list-group-item:first-child {\n border-top-width: 0;\n }\n}\n\n\n// Tables in panels\n//\n// Place a non-bordered `.table` within a panel (not within a `.panel-body`) and\n// watch it go full width.\n\n.panel {\n > .table,\n > .table-responsive > .table {\n margin-bottom: 0;\n }\n // Add border top radius for first one\n > .table:first-child,\n > .table-responsive:first-child > .table:first-child {\n .border-top-radius((@panel-border-radius - 1));\n\n > thead:first-child,\n > tbody:first-child {\n > tr:first-child {\n td:first-child,\n th:first-child {\n border-top-left-radius: (@panel-border-radius - 1);\n }\n td:last-child,\n th:last-child {\n border-top-right-radius: (@panel-border-radius - 1);\n }\n }\n }\n }\n // Add border bottom radius for last one\n > .table:last-child,\n > .table-responsive:last-child > .table:last-child {\n .border-bottom-radius((@panel-border-radius - 1));\n\n > tbody:last-child,\n > tfoot:last-child {\n > tr:last-child {\n td:first-child,\n th:first-child {\n border-bottom-left-radius: (@panel-border-radius - 1);\n }\n td:last-child,\n th:last-child {\n border-bottom-right-radius: (@panel-border-radius - 1);\n }\n }\n }\n }\n > .panel-body + .table,\n > .panel-body + .table-responsive {\n border-top: 1px solid @table-border-color;\n }\n > .table > tbody:first-child > tr:first-child th,\n > .table > tbody:first-child > tr:first-child td {\n border-top: 0;\n }\n > .table-bordered,\n > .table-responsive > .table-bordered {\n border: 0;\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th:first-child,\n > td:first-child {\n border-left: 0;\n }\n > th:last-child,\n > td:last-child {\n border-right: 0;\n }\n }\n }\n > thead,\n > tbody {\n > tr:first-child {\n > td,\n > th {\n border-bottom: 0;\n }\n }\n }\n > tbody,\n > tfoot {\n > tr:last-child {\n > td,\n > th {\n border-bottom: 0;\n }\n }\n }\n }\n > .table-responsive {\n border: 0;\n margin-bottom: 0;\n }\n}\n\n\n// Collapsable panels (aka, accordion)\n//\n// Wrap a series of panels in `.panel-group` to turn them into an accordion with\n// the help of our collapse JavaScript plugin.\n\n.panel-group {\n margin-bottom: @line-height-computed;\n\n // Tighten up margin so it's only between panels\n .panel {\n margin-bottom: 0;\n border-radius: @panel-border-radius;\n overflow: hidden; // crop contents when collapsed\n + .panel {\n margin-top: 5px;\n }\n }\n\n .panel-heading {\n border-bottom: 0;\n + .panel-collapse .panel-body {\n border-top: 1px solid @panel-inner-border;\n }\n }\n .panel-footer {\n border-top: 0;\n + .panel-collapse .panel-body {\n border-bottom: 1px solid @panel-inner-border;\n }\n }\n}\n\n\n// Contextual variations\n.panel-default {\n .panel-variant(@panel-default-border; @panel-default-text; @panel-default-heading-bg; @panel-default-border);\n}\n.panel-primary {\n .panel-variant(@panel-primary-border; @panel-primary-text; @panel-primary-heading-bg; @panel-primary-border);\n}\n.panel-success {\n .panel-variant(@panel-success-border; @panel-success-text; @panel-success-heading-bg; @panel-success-border);\n}\n.panel-info {\n .panel-variant(@panel-info-border; @panel-info-text; @panel-info-heading-bg; @panel-info-border);\n}\n.panel-warning {\n .panel-variant(@panel-warning-border; @panel-warning-text; @panel-warning-heading-bg; @panel-warning-border);\n}\n.panel-danger {\n .panel-variant(@panel-danger-border; @panel-danger-text; @panel-danger-heading-bg; @panel-danger-border);\n}\n","//\n// Wells\n// --------------------------------------------------\n\n\n// Base class\n.well {\n min-height: 20px;\n padding: 19px;\n margin-bottom: 20px;\n background-color: @well-bg;\n border: 1px solid @well-border;\n border-radius: @border-radius-base;\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.05));\n blockquote {\n border-color: #ddd;\n border-color: rgba(0,0,0,.15);\n }\n}\n\n// Sizes\n.well-lg {\n padding: 24px;\n border-radius: @border-radius-large;\n}\n.well-sm {\n padding: 9px;\n border-radius: @border-radius-small;\n}\n","//\n// Close icons\n// --------------------------------------------------\n\n\n.close {\n float: right;\n font-size: (@font-size-base * 1.5);\n font-weight: @close-font-weight;\n line-height: 1;\n color: @close-color;\n text-shadow: @close-text-shadow;\n .opacity(.2);\n\n &:hover,\n &:focus {\n color: @close-color;\n text-decoration: none;\n cursor: pointer;\n .opacity(.5);\n }\n\n // Additional properties for button version\n // iOS requires the button element instead of an anchor tag.\n // If you want the anchor version, it requires `href=\"#\"`.\n button& {\n padding: 0;\n cursor: pointer;\n background: transparent;\n border: 0;\n -webkit-appearance: none;\n }\n}\n","//\n// Modals\n// --------------------------------------------------\n\n// .modal-open - body class for killing the scroll\n// .modal - container to scroll within\n// .modal-dialog - positioning shell for the actual modal\n// .modal-content - actual modal w/ bg and corners and shit\n\n// Kill the scroll on the body\n.modal-open {\n overflow: hidden;\n}\n\n// Container that the modal scrolls within\n.modal {\n display: none;\n overflow: auto;\n overflow-y: scroll;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: @zindex-modal;\n -webkit-overflow-scrolling: touch;\n\n // Prevent Chrome on Windows from adding a focus outline. For details, see\n // https://github.com/twbs/bootstrap/pull/10951.\n outline: 0;\n\n // When fading in the modal, animate it to slide down\n &.fade .modal-dialog {\n .translate(0, -25%);\n .transition-transform(~\"0.3s ease-out\");\n }\n &.in .modal-dialog { .translate(0, 0)}\n}\n\n// Shell div to position the modal with bottom padding\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 10px;\n}\n\n// Actual modal\n.modal-content {\n position: relative;\n background-color: @modal-content-bg;\n border: 1px solid @modal-content-fallback-border-color; //old browsers fallback (ie8 etc)\n border: 1px solid @modal-content-border-color;\n border-radius: @border-radius-large;\n .box-shadow(0 3px 9px rgba(0,0,0,.5));\n background-clip: padding-box;\n // Remove focus outline from opened modal\n outline: none;\n}\n\n// Modal background\n.modal-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: @zindex-modal-background;\n background-color: @modal-backdrop-bg;\n // Fade for backdrop\n &.fade { .opacity(0); }\n &.in { .opacity(@modal-backdrop-opacity); }\n}\n\n// Modal header\n// Top section of the modal w/ title and dismiss\n.modal-header {\n padding: @modal-title-padding;\n border-bottom: 1px solid @modal-header-border-color;\n min-height: (@modal-title-padding + @modal-title-line-height);\n}\n// Close icon\n.modal-header .close {\n margin-top: -2px;\n}\n\n// Title text within header\n.modal-title {\n margin: 0;\n line-height: @modal-title-line-height;\n}\n\n// Modal body\n// Where all modal content resides (sibling of .modal-header and .modal-footer)\n.modal-body {\n position: relative;\n padding: @modal-inner-padding;\n}\n\n// Footer (for actions)\n.modal-footer {\n margin-top: 15px;\n padding: (@modal-inner-padding - 1) @modal-inner-padding @modal-inner-padding;\n text-align: right; // right align buttons\n border-top: 1px solid @modal-footer-border-color;\n &:extend(.clearfix all); // clear it in case folks use .pull-* classes on buttons\n\n // Properly space out buttons\n .btn + .btn {\n margin-left: 5px;\n margin-bottom: 0; // account for input[type=\"submit\"] which gets the bottom margin like all other inputs\n }\n // but override that for button groups\n .btn-group .btn + .btn {\n margin-left: -1px;\n }\n // and override it for block buttons as well\n .btn-block + .btn-block {\n margin-left: 0;\n }\n}\n\n// Scale up the modal\n@media (min-width: @screen-sm-min) {\n // Automatically set modal's width for larger viewports\n .modal-dialog {\n width: @modal-md;\n margin: 30px auto;\n }\n .modal-content {\n .box-shadow(0 5px 15px rgba(0,0,0,.5));\n }\n\n // Modal sizes\n .modal-sm { width: @modal-sm; }\n}\n\n@media (min-width: @screen-md-min) {\n .modal-lg { width: @modal-lg; }\n}\n","//\n// Tooltips\n// --------------------------------------------------\n\n\n// Base class\n.tooltip {\n position: absolute;\n z-index: @zindex-tooltip;\n display: block;\n visibility: visible;\n font-size: @font-size-small;\n line-height: 1.4;\n .opacity(0);\n\n &.in { .opacity(@tooltip-opacity); }\n &.top { margin-top: -3px; padding: @tooltip-arrow-width 0; }\n &.right { margin-left: 3px; padding: 0 @tooltip-arrow-width; }\n &.bottom { margin-top: 3px; padding: @tooltip-arrow-width 0; }\n &.left { margin-left: -3px; padding: 0 @tooltip-arrow-width; }\n}\n\n// Wrapper for the tooltip content\n.tooltip-inner {\n max-width: @tooltip-max-width;\n padding: 3px 8px;\n color: @tooltip-color;\n text-align: center;\n text-decoration: none;\n background-color: @tooltip-bg;\n border-radius: @border-radius-base;\n}\n\n// Arrows\n.tooltip-arrow {\n position: absolute;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.tooltip {\n &.top .tooltip-arrow {\n bottom: 0;\n left: 50%;\n margin-left: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n border-top-color: @tooltip-arrow-color;\n }\n &.top-left .tooltip-arrow {\n bottom: 0;\n left: @tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n border-top-color: @tooltip-arrow-color;\n }\n &.top-right .tooltip-arrow {\n bottom: 0;\n right: @tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n border-top-color: @tooltip-arrow-color;\n }\n &.right .tooltip-arrow {\n top: 50%;\n left: 0;\n margin-top: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width @tooltip-arrow-width 0;\n border-right-color: @tooltip-arrow-color;\n }\n &.left .tooltip-arrow {\n top: 50%;\n right: 0;\n margin-top: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-left-color: @tooltip-arrow-color;\n }\n &.bottom .tooltip-arrow {\n top: 0;\n left: 50%;\n margin-left: -@tooltip-arrow-width;\n border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-bottom-color: @tooltip-arrow-color;\n }\n &.bottom-left .tooltip-arrow {\n top: 0;\n left: @tooltip-arrow-width;\n border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-bottom-color: @tooltip-arrow-color;\n }\n &.bottom-right .tooltip-arrow {\n top: 0;\n right: @tooltip-arrow-width;\n border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-bottom-color: @tooltip-arrow-color;\n }\n}\n","//\n// Popovers\n// --------------------------------------------------\n\n\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: @zindex-popover;\n display: none;\n max-width: @popover-max-width;\n padding: 1px;\n text-align: left; // Reset given new insertion method\n background-color: @popover-bg;\n background-clip: padding-box;\n border: 1px solid @popover-fallback-border-color;\n border: 1px solid @popover-border-color;\n border-radius: @border-radius-large;\n .box-shadow(0 5px 10px rgba(0,0,0,.2));\n\n // Overrides for proper insertion\n white-space: normal;\n\n // Offset the popover to account for the popover arrow\n &.top { margin-top: -@popover-arrow-width; }\n &.right { margin-left: @popover-arrow-width; }\n &.bottom { margin-top: @popover-arrow-width; }\n &.left { margin-left: -@popover-arrow-width; }\n}\n\n.popover-title {\n margin: 0; // reset heading margin\n padding: 8px 14px;\n font-size: @font-size-base;\n font-weight: normal;\n line-height: 18px;\n background-color: @popover-title-bg;\n border-bottom: 1px solid darken(@popover-title-bg, 5%);\n border-radius: 5px 5px 0 0;\n}\n\n.popover-content {\n padding: 9px 14px;\n}\n\n// Arrows\n//\n// .arrow is outer, .arrow:after is inner\n\n.popover > .arrow {\n &,\n &:after {\n position: absolute;\n display: block;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n }\n}\n.popover > .arrow {\n border-width: @popover-arrow-outer-width;\n}\n.popover > .arrow:after {\n border-width: @popover-arrow-width;\n content: \"\";\n}\n\n.popover {\n &.top > .arrow {\n left: 50%;\n margin-left: -@popover-arrow-outer-width;\n border-bottom-width: 0;\n border-top-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-top-color: @popover-arrow-outer-color;\n bottom: -@popover-arrow-outer-width;\n &:after {\n content: \" \";\n bottom: 1px;\n margin-left: -@popover-arrow-width;\n border-bottom-width: 0;\n border-top-color: @popover-arrow-color;\n }\n }\n &.right > .arrow {\n top: 50%;\n left: -@popover-arrow-outer-width;\n margin-top: -@popover-arrow-outer-width;\n border-left-width: 0;\n border-right-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-right-color: @popover-arrow-outer-color;\n &:after {\n content: \" \";\n left: 1px;\n bottom: -@popover-arrow-width;\n border-left-width: 0;\n border-right-color: @popover-arrow-color;\n }\n }\n &.bottom > .arrow {\n left: 50%;\n margin-left: -@popover-arrow-outer-width;\n border-top-width: 0;\n border-bottom-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-bottom-color: @popover-arrow-outer-color;\n top: -@popover-arrow-outer-width;\n &:after {\n content: \" \";\n top: 1px;\n margin-left: -@popover-arrow-width;\n border-top-width: 0;\n border-bottom-color: @popover-arrow-color;\n }\n }\n\n &.left > .arrow {\n top: 50%;\n right: -@popover-arrow-outer-width;\n margin-top: -@popover-arrow-outer-width;\n border-right-width: 0;\n border-left-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-left-color: @popover-arrow-outer-color;\n &:after {\n content: \" \";\n right: 1px;\n border-right-width: 0;\n border-left-color: @popover-arrow-color;\n bottom: -@popover-arrow-width;\n }\n }\n\n}\n","//\n// Responsive: Utility classes\n// --------------------------------------------------\n\n\n// IE10 in Windows (Phone) 8\n//\n// Support for responsive views via media queries is kind of borked in IE10, for\n// Surface/desktop in split view and for Windows Phone 8. This particular fix\n// must be accompanied by a snippet of JavaScript to sniff the user agent and\n// apply some conditional CSS to *only* the Surface/desktop Windows 8. Look at\n// our Getting Started page for more information on this bug.\n//\n// For more information, see the following:\n//\n// Issue: https://github.com/twbs/bootstrap/issues/10497\n// Docs: http://getbootstrap.com/getting-started/#browsers\n// Source: http://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/\n\n@-ms-viewport {\n width: device-width;\n}\n\n\n// Visibility utilities\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n .responsive-invisibility();\n}\n\n.visible-xs {\n @media (max-width: @screen-xs-max) {\n .responsive-visibility();\n }\n}\n.visible-sm {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n .responsive-visibility();\n }\n}\n.visible-md {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n .responsive-visibility();\n }\n}\n.visible-lg {\n @media (min-width: @screen-lg-min) {\n .responsive-visibility();\n }\n}\n\n.hidden-xs {\n @media (max-width: @screen-xs-max) {\n .responsive-invisibility();\n }\n}\n.hidden-sm {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n .responsive-invisibility();\n }\n}\n.hidden-md {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n .responsive-invisibility();\n }\n}\n.hidden-lg {\n @media (min-width: @screen-lg-min) {\n .responsive-invisibility();\n }\n}\n\n\n// Print utilities\n//\n// Media queries are placed on the inside to be mixin-friendly.\n\n.visible-print {\n .responsive-invisibility();\n\n @media print {\n .responsive-visibility();\n }\n}\n\n.hidden-print {\n @media print {\n .responsive-invisibility();\n }\n}\n"]} -\ No newline at end of file -diff --git a/ui/bootstrap/css/bootstrap.min.css b/ui/bootstrap/css/bootstrap.min.css -new file mode 100644 -index 0000000..679272d ---- /dev/null -+++ b/ui/bootstrap/css/bootstrap.min.css -@@ -0,0 +1,7 @@ -+/*! -+ * Bootstrap v3.1.1 (http://getbootstrap.com) -+ * Copyright 2011-2014 Twitter, Inc. -+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) -+ */ -+ -+/*! normalize.css v3.0.0 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:0 0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@media print{*{text-shadow:none!important;color:#000!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:before,:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive,.thumbnail>img,.thumbnail a>img,.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:400;line-height:1;color:#999}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:200;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-muted{color:#999}.text-primary{color:#428bca}a.text-primary:hover{color:#3071a9}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#428bca}a.bg-primary:hover{background-color:#3071a9}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none;margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857143;color:#999}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;white-space:nowrap;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;word-break:break-all;word-wrap:break-word;color:#333;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:0}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:0}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:0}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:0}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:0}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:0}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:0}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:0}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*=col-]{position:static;float:none;display:table-column}table td[class*=col-],table th[class*=col-]{position:static;float:none;display:table-cell}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}@media (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;overflow-x:scroll;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0;min-width:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=radio],input[type=checkbox]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=radio]:focus,input[type=checkbox]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee;opacity:1}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}input[type=date]{line-height:34px}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;margin-top:10px;margin-bottom:10px;padding-left:20px}.radio label,.checkbox label{display:inline;font-weight:400;cursor:pointer}.radio input[type=radio],.radio-inline input[type=radio],.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:400;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type=radio][disabled],input[type=checkbox][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type=radio],fieldset[disabled] input[type=checkbox],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm,select[multiple].input-sm{height:auto}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:46px;line-height:46px}textarea.input-lg,select[multiple].input-lg{height:auto}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.has-feedback .form-control-feedback{position:absolute;top:25px;right:0;display:block;width:34px;height:34px;line-height:34px;text-align:center}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;border-color:#3c763d;background-color:#dff0d8}.has-success .form-control-feedback{color:#3c763d}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;border-color:#8a6d3b;background-color:#fcf8e3}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;border-color:#a94442;background-color:#f2dede}.has-error .form-control-feedback{color:#a94442}.form-control-static{margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;padding-left:0;vertical-align:middle}.form-inline .radio input[type=radio],.form-inline .checkbox input[type=checkbox]{float:none;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{margin-top:0;margin-bottom:0;padding-top:7px}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}.form-horizontal .form-control-static{padding-top:7px}@media (min-width:768px){.form-horizontal .control-label{text-align:right}}.form-horizontal .has-feedback .form-control-feedback{top:0;right:15px}.btn{display:inline-block;margin-bottom:0;font-weight:400;text-align:center;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;line-height:1.42857143;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn:focus,.btn:active:focus,.btn.active:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;pointer-events:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#333;background-color:#ebebeb;border-color:#adadad}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-primary .badge{color:#428bca;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#47a447;border-color:#398439}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#39b3d7;border-color:#269abc}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#ed9c28;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#d2322d;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{color:#428bca;font-weight:400;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%;padding-left:0;padding-right:0}.btn-block+.btn-block{margin-top:5px}input[type=submit].btn-block,input[type=reset].btn-block,input[type=button].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:14px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{text-decoration:none;color:#262626;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;outline:0;background-color:#428bca}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#999}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media (min-width:768px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-bottom-left-radius:4px;border-top-right-radius:0;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}[data-toggle=buttons]>.btn>input[type=radio],[data-toggle=buttons]>.btn>input[type=checkbox]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-left:0;padding-right:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=radio],.input-group-addon input[type=checkbox]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-left:0;padding-right:0}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px;font-size:18px;line-height:20px;height:50px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:8px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}.navbar-nav.navbar-right:last-child{margin-right:-15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{margin-left:-15px;margin-right:-15px;padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);margin-top:8px;margin-bottom:8px}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;padding-left:0;vertical-align:middle}.navbar-form .radio input[type=radio],.navbar-form .checkbox input[type=checkbox]{float:none;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media (min-width:768px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;-webkit-box-shadow:none;box-shadow:none}.navbar-form.navbar-right:last-child{margin-right:-15px}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-left:15px;margin-right:15px}.navbar-text.navbar-right:last-child{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{background-color:#e7e7e7;color:#555}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{background-color:#080808;color:#fff}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{content:"/\00a0";padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;line-height:1.42857143;text-decoration:none;color:#428bca;background-color:#fff;border:1px solid #ddd;margin-left:-1px}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-bottom-right-radius:4px;border-top-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{color:#2a6496;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca;cursor:default}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;background-color:#fff;border-color:#ddd;cursor:not-allowed}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-bottom-right-radius:6px;border-top-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-bottom-right-radius:3px;border-top-right-radius:3px}.pager{padding-left:0;margin:20px 0;list-style:none;text-align:center}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;background-color:#fff;cursor:not-allowed}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:gray}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;color:#fff;line-height:1;vertical-align:baseline;white-space:nowrap;text-align:center;background-color:#999;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.container .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-left:60px;padding-right:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img,.thumbnail a>img{margin-left:auto;margin-right:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#3c763d}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#31708f}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{background-color:#fcf8e3;border-color:#faebcc;color:#8a6d3b}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{background-color:#f2dede;border-color:#ebccd1;color:#a94442}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{margin-bottom:20px;padding-left:0}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}a.list-group-item.active .list-group-item-heading,a.list-group-item.active:hover .list-group-item-heading,a.list-group-item.active:focus .list-group-item-heading{color:inherit}a.list-group-item.active .list-group-item-text,a.list-group-item.active:hover .list-group-item-text,a.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.list-group-item-info.active:focus{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-right-radius:3px;border-top-left-radius:3px}.panel>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-right-radius:3px;border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{border:0;margin-bottom:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px;overflow:hidden}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d6e9c6}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#bce8f1}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#faebcc}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#ebccd1}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ebccd1}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{display:none;overflow:auto;overflow-y:scroll;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5);background-clip:padding-box;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5;min-height:16.42857143px}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:20px}.modal-footer{margin-top:15px;padding:19px 20px 20px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1030;display:block;visibility:visible;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;right:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);white-space:normal}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:400;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{border-width:10px;content:""}.popover.top>.arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,.25);bottom:-11px}.popover.top>.arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,.25)}.popover.right>.arrow:after{content:" ";left:1px;bottom:-10px;border-left-width:0;border-right-color:#fff}.popover.bottom>.arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25);top:-11px}.popover.bottom>.arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{content:" ";right:1px;border-right-width:0;border-left-color:#fff;bottom:-10px}.carousel{position:relative}.carousel-inner{position:relative;overflow:hidden;width:100%}.carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;left:0;bottom:0;width:15%;opacity:.5;filter:alpha(opacity=50);font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-control.left{background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,.5) 0),color-stop(rgba(0,0,0,.0001) 100%));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1)}.carousel-control.right{left:auto;right:0;background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,.0001) 0),color-stop(rgba(0,0,0,.5) 100%));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.carousel-control:hover,.carousel-control:focus{outline:0;color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;margin-left:-30%;padding-left:0;list-style:none;text-align:center}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;border:1px solid #fff;border-radius:10px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0)}.carousel-indicators .active{margin:0;width:12px;height:12px;background-color:#fff}.carousel-caption{position:absolute;left:15%;right:15%;bottom:20px;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{left:20%;right:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-footer:before,.modal-footer:after{content:" ";display:table}.clearfix:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-footer:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}}@media print{.hidden-print{display:none!important}} -\ No newline at end of file -diff --git a/ui/bootstrap/fonts/glyphicons-halflings-regular.eot b/ui/bootstrap/fonts/glyphicons-halflings-regular.eot -new file mode 100644 -index 0000000..4a4ca86 -Binary files /dev/null and b/ui/bootstrap/fonts/glyphicons-halflings-regular.eot differ -diff --git a/ui/bootstrap/fonts/glyphicons-halflings-regular.svg b/ui/bootstrap/fonts/glyphicons-halflings-regular.svg -new file mode 100644 -index 0000000..e3e2dc7 ---- /dev/null -+++ b/ui/bootstrap/fonts/glyphicons-halflings-regular.svg -@@ -0,0 +1,229 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -\ No newline at end of file -diff --git a/ui/bootstrap/fonts/glyphicons-halflings-regular.ttf b/ui/bootstrap/fonts/glyphicons-halflings-regular.ttf -new file mode 100644 -index 0000000..67fa00b -Binary files /dev/null and b/ui/bootstrap/fonts/glyphicons-halflings-regular.ttf differ -diff --git a/ui/bootstrap/fonts/glyphicons-halflings-regular.woff b/ui/bootstrap/fonts/glyphicons-halflings-regular.woff -new file mode 100644 -index 0000000..8c54182 -Binary files /dev/null and b/ui/bootstrap/fonts/glyphicons-halflings-regular.woff differ -diff --git a/ui/bootstrap/js/bootstrap.js b/ui/bootstrap/js/bootstrap.js -new file mode 100644 -index 0000000..8ae571b ---- /dev/null -+++ b/ui/bootstrap/js/bootstrap.js -@@ -0,0 +1,1951 @@ -+/*! -+ * Bootstrap v3.1.1 (http://getbootstrap.com) -+ * Copyright 2011-2014 Twitter, Inc. -+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) -+ */ -+ -+if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript requires jQuery') } -+ -+/* ======================================================================== -+ * Bootstrap: transition.js v3.1.1 -+ * http://getbootstrap.com/javascript/#transitions -+ * ======================================================================== -+ * Copyright 2011-2014 Twitter, Inc. -+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) -+ * ======================================================================== */ -+ -+ -++function ($) { -+ 'use strict'; -+ -+ // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) -+ // ============================================================ -+ -+ function transitionEnd() { -+ var el = document.createElement('bootstrap') -+ -+ var transEndEventNames = { -+ 'WebkitTransition' : 'webkitTransitionEnd', -+ 'MozTransition' : 'transitionend', -+ 'OTransition' : 'oTransitionEnd otransitionend', -+ 'transition' : 'transitionend' -+ } -+ -+ for (var name in transEndEventNames) { -+ if (el.style[name] !== undefined) { -+ return { end: transEndEventNames[name] } -+ } -+ } -+ -+ return false // explicit for ie8 ( ._.) -+ } -+ -+ // http://blog.alexmaccaw.com/css-transitions -+ $.fn.emulateTransitionEnd = function (duration) { -+ var called = false, $el = this -+ $(this).one($.support.transition.end, function () { called = true }) -+ var callback = function () { if (!called) $($el).trigger($.support.transition.end) } -+ setTimeout(callback, duration) -+ return this -+ } -+ -+ $(function () { -+ $.support.transition = transitionEnd() -+ }) -+ -+}(jQuery); -+ -+/* ======================================================================== -+ * Bootstrap: alert.js v3.1.1 -+ * http://getbootstrap.com/javascript/#alerts -+ * ======================================================================== -+ * Copyright 2011-2014 Twitter, Inc. -+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) -+ * ======================================================================== */ -+ -+ -++function ($) { -+ 'use strict'; -+ -+ // ALERT CLASS DEFINITION -+ // ====================== -+ -+ var dismiss = '[data-dismiss="alert"]' -+ var Alert = function (el) { -+ $(el).on('click', dismiss, this.close) -+ } -+ -+ Alert.prototype.close = function (e) { -+ var $this = $(this) -+ var selector = $this.attr('data-target') -+ -+ if (!selector) { -+ selector = $this.attr('href') -+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 -+ } -+ -+ var $parent = $(selector) -+ -+ if (e) e.preventDefault() -+ -+ if (!$parent.length) { -+ $parent = $this.hasClass('alert') ? $this : $this.parent() -+ } -+ -+ $parent.trigger(e = $.Event('close.bs.alert')) -+ -+ if (e.isDefaultPrevented()) return -+ -+ $parent.removeClass('in') -+ -+ function removeElement() { -+ $parent.trigger('closed.bs.alert').remove() -+ } -+ -+ $.support.transition && $parent.hasClass('fade') ? -+ $parent -+ .one($.support.transition.end, removeElement) -+ .emulateTransitionEnd(150) : -+ removeElement() -+ } -+ -+ -+ // ALERT PLUGIN DEFINITION -+ // ======================= -+ -+ var old = $.fn.alert -+ -+ $.fn.alert = function (option) { -+ return this.each(function () { -+ var $this = $(this) -+ var data = $this.data('bs.alert') -+ -+ if (!data) $this.data('bs.alert', (data = new Alert(this))) -+ if (typeof option == 'string') data[option].call($this) -+ }) -+ } -+ -+ $.fn.alert.Constructor = Alert -+ -+ -+ // ALERT NO CONFLICT -+ // ================= -+ -+ $.fn.alert.noConflict = function () { -+ $.fn.alert = old -+ return this -+ } -+ -+ -+ // ALERT DATA-API -+ // ============== -+ -+ $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) -+ -+}(jQuery); -+ -+/* ======================================================================== -+ * Bootstrap: button.js v3.1.1 -+ * http://getbootstrap.com/javascript/#buttons -+ * ======================================================================== -+ * Copyright 2011-2014 Twitter, Inc. -+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) -+ * ======================================================================== */ -+ -+ -++function ($) { -+ 'use strict'; -+ -+ // BUTTON PUBLIC CLASS DEFINITION -+ // ============================== -+ -+ var Button = function (element, options) { -+ this.$element = $(element) -+ this.options = $.extend({}, Button.DEFAULTS, options) -+ this.isLoading = false -+ } -+ -+ Button.DEFAULTS = { -+ loadingText: 'loading...' -+ } -+ -+ Button.prototype.setState = function (state) { -+ var d = 'disabled' -+ var $el = this.$element -+ var val = $el.is('input') ? 'val' : 'html' -+ var data = $el.data() -+ -+ state = state + 'Text' -+ -+ if (!data.resetText) $el.data('resetText', $el[val]()) -+ -+ $el[val](data[state] || this.options[state]) -+ -+ // push to event loop to allow forms to submit -+ setTimeout($.proxy(function () { -+ if (state == 'loadingText') { -+ this.isLoading = true -+ $el.addClass(d).attr(d, d) -+ } else if (this.isLoading) { -+ this.isLoading = false -+ $el.removeClass(d).removeAttr(d) -+ } -+ }, this), 0) -+ } -+ -+ Button.prototype.toggle = function () { -+ var changed = true -+ var $parent = this.$element.closest('[data-toggle="buttons"]') -+ -+ if ($parent.length) { -+ var $input = this.$element.find('input') -+ if ($input.prop('type') == 'radio') { -+ if ($input.prop('checked') && this.$element.hasClass('active')) changed = false -+ else $parent.find('.active').removeClass('active') -+ } -+ if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') -+ } -+ -+ if (changed) this.$element.toggleClass('active') -+ } -+ -+ -+ // BUTTON PLUGIN DEFINITION -+ // ======================== -+ -+ var old = $.fn.button -+ -+ $.fn.button = function (option) { -+ return this.each(function () { -+ var $this = $(this) -+ var data = $this.data('bs.button') -+ var options = typeof option == 'object' && option -+ -+ if (!data) $this.data('bs.button', (data = new Button(this, options))) -+ -+ if (option == 'toggle') data.toggle() -+ else if (option) data.setState(option) -+ }) -+ } -+ -+ $.fn.button.Constructor = Button -+ -+ -+ // BUTTON NO CONFLICT -+ // ================== -+ -+ $.fn.button.noConflict = function () { -+ $.fn.button = old -+ return this -+ } -+ -+ -+ // BUTTON DATA-API -+ // =============== -+ -+ $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) { -+ var $btn = $(e.target) -+ if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') -+ $btn.button('toggle') -+ e.preventDefault() -+ }) -+ -+}(jQuery); -+ -+/* ======================================================================== -+ * Bootstrap: carousel.js v3.1.1 -+ * http://getbootstrap.com/javascript/#carousel -+ * ======================================================================== -+ * Copyright 2011-2014 Twitter, Inc. -+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) -+ * ======================================================================== */ -+ -+ -++function ($) { -+ 'use strict'; -+ -+ // CAROUSEL CLASS DEFINITION -+ // ========================= -+ -+ var Carousel = function (element, options) { -+ this.$element = $(element) -+ this.$indicators = this.$element.find('.carousel-indicators') -+ this.options = options -+ this.paused = -+ this.sliding = -+ this.interval = -+ this.$active = -+ this.$items = null -+ -+ this.options.pause == 'hover' && this.$element -+ .on('mouseenter', $.proxy(this.pause, this)) -+ .on('mouseleave', $.proxy(this.cycle, this)) -+ } -+ -+ Carousel.DEFAULTS = { -+ interval: 5000, -+ pause: 'hover', -+ wrap: true -+ } -+ -+ Carousel.prototype.cycle = function (e) { -+ e || (this.paused = false) -+ -+ this.interval && clearInterval(this.interval) -+ -+ this.options.interval -+ && !this.paused -+ && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) -+ -+ return this -+ } -+ -+ Carousel.prototype.getActiveIndex = function () { -+ this.$active = this.$element.find('.item.active') -+ this.$items = this.$active.parent().children() -+ -+ return this.$items.index(this.$active) -+ } -+ -+ Carousel.prototype.to = function (pos) { -+ var that = this -+ var activeIndex = this.getActiveIndex() -+ -+ if (pos > (this.$items.length - 1) || pos < 0) return -+ -+ if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) -+ if (activeIndex == pos) return this.pause().cycle() -+ -+ return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) -+ } -+ -+ Carousel.prototype.pause = function (e) { -+ e || (this.paused = true) -+ -+ if (this.$element.find('.next, .prev').length && $.support.transition) { -+ this.$element.trigger($.support.transition.end) -+ this.cycle(true) -+ } -+ -+ this.interval = clearInterval(this.interval) -+ -+ return this -+ } -+ -+ Carousel.prototype.next = function () { -+ if (this.sliding) return -+ return this.slide('next') -+ } -+ -+ Carousel.prototype.prev = function () { -+ if (this.sliding) return -+ return this.slide('prev') -+ } -+ -+ Carousel.prototype.slide = function (type, next) { -+ var $active = this.$element.find('.item.active') -+ var $next = next || $active[type]() -+ var isCycling = this.interval -+ var direction = type == 'next' ? 'left' : 'right' -+ var fallback = type == 'next' ? 'first' : 'last' -+ var that = this -+ -+ if (!$next.length) { -+ if (!this.options.wrap) return -+ $next = this.$element.find('.item')[fallback]() -+ } -+ -+ if ($next.hasClass('active')) return this.sliding = false -+ -+ var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction }) -+ this.$element.trigger(e) -+ if (e.isDefaultPrevented()) return -+ -+ this.sliding = true -+ -+ isCycling && this.pause() -+ -+ if (this.$indicators.length) { -+ this.$indicators.find('.active').removeClass('active') -+ this.$element.one('slid.bs.carousel', function () { -+ var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) -+ $nextIndicator && $nextIndicator.addClass('active') -+ }) -+ } -+ -+ if ($.support.transition && this.$element.hasClass('slide')) { -+ $next.addClass(type) -+ $next[0].offsetWidth // force reflow -+ $active.addClass(direction) -+ $next.addClass(direction) -+ $active -+ .one($.support.transition.end, function () { -+ $next.removeClass([type, direction].join(' ')).addClass('active') -+ $active.removeClass(['active', direction].join(' ')) -+ that.sliding = false -+ setTimeout(function () { that.$element.trigger('slid.bs.carousel') }, 0) -+ }) -+ .emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000) -+ } else { -+ $active.removeClass('active') -+ $next.addClass('active') -+ this.sliding = false -+ this.$element.trigger('slid.bs.carousel') -+ } -+ -+ isCycling && this.cycle() -+ -+ return this -+ } -+ -+ -+ // CAROUSEL PLUGIN DEFINITION -+ // ========================== -+ -+ var old = $.fn.carousel -+ -+ $.fn.carousel = function (option) { -+ return this.each(function () { -+ var $this = $(this) -+ var data = $this.data('bs.carousel') -+ var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) -+ var action = typeof option == 'string' ? option : options.slide -+ -+ if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) -+ if (typeof option == 'number') data.to(option) -+ else if (action) data[action]() -+ else if (options.interval) data.pause().cycle() -+ }) -+ } -+ -+ $.fn.carousel.Constructor = Carousel -+ -+ -+ // CAROUSEL NO CONFLICT -+ // ==================== -+ -+ $.fn.carousel.noConflict = function () { -+ $.fn.carousel = old -+ return this -+ } -+ -+ -+ // CAROUSEL DATA-API -+ // ================= -+ -+ $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { -+ var $this = $(this), href -+ var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 -+ var options = $.extend({}, $target.data(), $this.data()) -+ var slideIndex = $this.attr('data-slide-to') -+ if (slideIndex) options.interval = false -+ -+ $target.carousel(options) -+ -+ if (slideIndex = $this.attr('data-slide-to')) { -+ $target.data('bs.carousel').to(slideIndex) -+ } -+ -+ e.preventDefault() -+ }) -+ -+ $(window).on('load', function () { -+ $('[data-ride="carousel"]').each(function () { -+ var $carousel = $(this) -+ $carousel.carousel($carousel.data()) -+ }) -+ }) -+ -+}(jQuery); -+ -+/* ======================================================================== -+ * Bootstrap: collapse.js v3.1.1 -+ * http://getbootstrap.com/javascript/#collapse -+ * ======================================================================== -+ * Copyright 2011-2014 Twitter, Inc. -+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) -+ * ======================================================================== */ -+ -+ -++function ($) { -+ 'use strict'; -+ -+ // COLLAPSE PUBLIC CLASS DEFINITION -+ // ================================ -+ -+ var Collapse = function (element, options) { -+ this.$element = $(element) -+ this.options = $.extend({}, Collapse.DEFAULTS, options) -+ this.transitioning = null -+ -+ if (this.options.parent) this.$parent = $(this.options.parent) -+ if (this.options.toggle) this.toggle() -+ } -+ -+ Collapse.DEFAULTS = { -+ toggle: true -+ } -+ -+ Collapse.prototype.dimension = function () { -+ var hasWidth = this.$element.hasClass('width') -+ return hasWidth ? 'width' : 'height' -+ } -+ -+ Collapse.prototype.show = function () { -+ if (this.transitioning || this.$element.hasClass('in')) return -+ -+ var startEvent = $.Event('show.bs.collapse') -+ this.$element.trigger(startEvent) -+ if (startEvent.isDefaultPrevented()) return -+ -+ var actives = this.$parent && this.$parent.find('> .panel > .in') -+ -+ if (actives && actives.length) { -+ var hasData = actives.data('bs.collapse') -+ if (hasData && hasData.transitioning) return -+ actives.collapse('hide') -+ hasData || actives.data('bs.collapse', null) -+ } -+ -+ var dimension = this.dimension() -+ -+ this.$element -+ .removeClass('collapse') -+ .addClass('collapsing') -+ [dimension](0) -+ -+ this.transitioning = 1 -+ -+ var complete = function () { -+ this.$element -+ .removeClass('collapsing') -+ .addClass('collapse in') -+ [dimension]('auto') -+ this.transitioning = 0 -+ this.$element.trigger('shown.bs.collapse') -+ } -+ -+ if (!$.support.transition) return complete.call(this) -+ -+ var scrollSize = $.camelCase(['scroll', dimension].join('-')) -+ -+ this.$element -+ .one($.support.transition.end, $.proxy(complete, this)) -+ .emulateTransitionEnd(350) -+ [dimension](this.$element[0][scrollSize]) -+ } -+ -+ Collapse.prototype.hide = function () { -+ if (this.transitioning || !this.$element.hasClass('in')) return -+ -+ var startEvent = $.Event('hide.bs.collapse') -+ this.$element.trigger(startEvent) -+ if (startEvent.isDefaultPrevented()) return -+ -+ var dimension = this.dimension() -+ -+ this.$element -+ [dimension](this.$element[dimension]()) -+ [0].offsetHeight -+ -+ this.$element -+ .addClass('collapsing') -+ .removeClass('collapse') -+ .removeClass('in') -+ -+ this.transitioning = 1 -+ -+ var complete = function () { -+ this.transitioning = 0 -+ this.$element -+ .trigger('hidden.bs.collapse') -+ .removeClass('collapsing') -+ .addClass('collapse') -+ } -+ -+ if (!$.support.transition) return complete.call(this) -+ -+ this.$element -+ [dimension](0) -+ .one($.support.transition.end, $.proxy(complete, this)) -+ .emulateTransitionEnd(350) -+ } -+ -+ Collapse.prototype.toggle = function () { -+ this[this.$element.hasClass('in') ? 'hide' : 'show']() -+ } -+ -+ -+ // COLLAPSE PLUGIN DEFINITION -+ // ========================== -+ -+ var old = $.fn.collapse -+ -+ $.fn.collapse = function (option) { -+ return this.each(function () { -+ var $this = $(this) -+ var data = $this.data('bs.collapse') -+ var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) -+ -+ if (!data && options.toggle && option == 'show') option = !option -+ if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) -+ if (typeof option == 'string') data[option]() -+ }) -+ } -+ -+ $.fn.collapse.Constructor = Collapse -+ -+ -+ // COLLAPSE NO CONFLICT -+ // ==================== -+ -+ $.fn.collapse.noConflict = function () { -+ $.fn.collapse = old -+ return this -+ } -+ -+ -+ // COLLAPSE DATA-API -+ // ================= -+ -+ $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) { -+ var $this = $(this), href -+ var target = $this.attr('data-target') -+ || e.preventDefault() -+ || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 -+ var $target = $(target) -+ var data = $target.data('bs.collapse') -+ var option = data ? 'toggle' : $this.data() -+ var parent = $this.attr('data-parent') -+ var $parent = parent && $(parent) -+ -+ if (!data || !data.transitioning) { -+ if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed') -+ $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') -+ } -+ -+ $target.collapse(option) -+ }) -+ -+}(jQuery); -+ -+/* ======================================================================== -+ * Bootstrap: dropdown.js v3.1.1 -+ * http://getbootstrap.com/javascript/#dropdowns -+ * ======================================================================== -+ * Copyright 2011-2014 Twitter, Inc. -+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) -+ * ======================================================================== */ -+ -+ -++function ($) { -+ 'use strict'; -+ -+ // DROPDOWN CLASS DEFINITION -+ // ========================= -+ -+ var backdrop = '.dropdown-backdrop' -+ var toggle = '[data-toggle=dropdown]' -+ var Dropdown = function (element) { -+ $(element).on('click.bs.dropdown', this.toggle) -+ } -+ -+ Dropdown.prototype.toggle = function (e) { -+ var $this = $(this) -+ -+ if ($this.is('.disabled, :disabled')) return -+ -+ var $parent = getParent($this) -+ var isActive = $parent.hasClass('open') -+ -+ clearMenus() -+ -+ if (!isActive) { -+ if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { -+ // if mobile we use a backdrop because click events don't delegate -+ $('
    -+
    -+ -+ -+ -+ -+

    -+ {% include "footer.html" %} -+ -+ -\ No newline at end of file -diff --git a/ui/editpost.html b/ui/editpost.html -new file mode 100644 -index 0000000..643f706 ---- /dev/null -+++ b/ui/editpost.html -@@ -0,0 +1,74 @@ -+ -+ -+ -+ -+ -+ -+ Edit Post -+ -+ -+ {% include "header.html" %} -+





    -+ -+

    Malaria : infoHub

    -+ -+
    -+
    -+

    Edit Post

    -+
    -+ -+ -+
    -+ -+
    -+
    -+
    -+
    -+

    Title

    -+
    -+
    -+ -+
    -+
    -+
    -+
    -+
    -+
    -+

    Descrpition

    -+
    -+
    -+ -+ -+
    -+
    -+
    -+ -+
    -+
    -+
    -+
    -+ -+
    -+
    -+
    -+
    -+
    -+
    -+ -+ -+ -+ -+ -+ -+ -+ -+

    -+ {% include "footer.html" %} -+ -+ -+ -\ No newline at end of file -diff --git a/ui/footer.html b/ui/footer.html -new file mode 100644 -index 0000000..c6738ed ---- /dev/null -+++ b/ui/footer.html -@@ -0,0 +1,65 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
    -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+

    ©2014 PeaceCrops

    -+ -+ Return to Top -+
    -\ No newline at end of file -diff --git a/ui/header.html b/ui/header.html -new file mode 100644 -index 0000000..a0b464f ---- /dev/null -+++ b/ui/header.html -@@ -0,0 +1,45 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -\ No newline at end of file -diff --git a/ui/index.html b/ui/index.html -new file mode 100644 -index 0000000..5c0209b ---- /dev/null -+++ b/ui/index.html -@@ -0,0 +1,44 @@ -+ -+ -+ -+ -+ -+ -+ Welcome ! -+ -+ -+ -+ {% include "header.html" %} -+





    -+ -+
    -+ -+
    -+
    -+
    -+

    Log in

    -+
    -+

    Username :

    -+ -+

    Password :

    -+ -+

    -+ -+
    -+

    -+
    -+ -+
    -+ -+

    -+ {% include "footer.html" %} -+ -+ -+ -+ -+ -diff --git a/ui/index.html~ b/ui/index.html~ -new file mode 100644 -index 0000000..933c11c ---- /dev/null -+++ b/ui/index.html~ -@@ -0,0 +1,9 @@ -+ -+ -+ Welcome ! Dashboard -+ -+ -+

    Yes Vaibhavi, you have done it

    -+ -+ -+ -diff --git a/ui/malaria.html b/ui/malaria.html -new file mode 100644 -index 0000000..3556ec0 ---- /dev/null -+++ b/ui/malaria.html -@@ -0,0 +1,59 @@ -+ -+ -+ -+ -+ -+ -+ -+ Malaria | infoHub -+ -+ -+ {% include "header.html" %} -+





    -+

    Malaria : infoHub

    -+
    -+

    -+ -+ -+ -+ {%if all_posts|length ==0 %} -+

    There are No Posts right now.











    -+ {% else %} -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ {% for post in all_posts %} -+ -+ -+ -+ {% endfor %} -+ -+ -+ -+ -+

    Post

    Action

    {{post.title_post}}     -+
    -+ {% endif %} -+ -+ -+
    -+ -+

    -+ {% include "footer.html" %} -+ -+ -+ -+ -diff --git a/ui/newpost.html b/ui/newpost.html -new file mode 100644 -index 0000000..1a09c6a ---- /dev/null -+++ b/ui/newpost.html -@@ -0,0 +1,68 @@ -+ -+ -+ -+ -+ -+ Add New Post -+ -+ -+ {% include "header.html" %} -+





    -+

    Malaria : infoHub

    -+ -+
    -+
    -+

    New Post

    -+
    -+ -+
    -+ -+
    -+
    -+
    -+
    -+

    Title

    -+
    -+
    -+ -+
    -+
    -+
    -+
    -+
    -+
    -+

    Descrpition

    -+
    -+
    -+ -+ -+
    -+
    -+
    -+ -+
    -+
    -+
    -+
    -+ -+
    -+
    -+
    -+
    -+
    -+
    -+ -+ -+ -+ -+ -+


    -+ {% include "footer.html" %} -+ -+ -+ -\ No newline at end of file -diff --git a/ui/notice.html b/ui/notice.html -new file mode 100644 -index 0000000..d0fccd8 ---- /dev/null -+++ b/ui/notice.html -@@ -0,0 +1,23 @@ -+ -+ -+ -+ -+ -+ Notice -+ -+ -+ {% include "header.html" %} -+







    -+

    {{text}}

    -+

    {{text1}}

    -+












    -+ {% include "footer.html" %} -+ -+ -+ -+ -diff --git a/ui/peacetrack.html b/ui/peacetrack.html -new file mode 100644 -index 0000000..f561a87 ---- /dev/null -+++ b/ui/peacetrack.html -@@ -0,0 +1,22 @@ -+ -+ -+ -+ -+ -+ PeaceTrack -+ -+ -+ {% include "header.html" %} -+





    -+

    Here the information about peacetrack would be shown

    -+ -+

















    -+ {% include "footer.html" %} -+ -+ -+ -diff --git a/ui/profile.html b/ui/profile.html -new file mode 100644 -index 0000000..cb717ee ---- /dev/null -+++ b/ui/profile.html -@@ -0,0 +1,52 @@ -+ -+ -+ -+ -+ -+ -+ User Profile | {{profiler.first_name}} -+ -+ -+ {% include "header.html" %} -+





    -+ -+
    -+
    -+

    User Profile

    -+
    -+
    -+
    -+
    -+
    -+
    -+

    First Name : {{profiler.user.first_name}}

    -+

    Last Name : {{profiler.user.last_name}}

    -+

    Email Address : {{profiler.user.email}}

    -+

    Mobile : {{profiler.phone}}

    -+

    Gender : {{profiler.gender}}

    -+

    Location : {{profiler.location}}

    -+ -+
    -+
    -+
    -+ -+

    User {{profiler.user}}

    -+
    -+
    -+ -+
    -+
    -+

    -+
    -+ -+ -+
    -+

    -+ {% include "footer.html" %} -+ -+ -\ No newline at end of file -diff --git a/ui/redirect.html b/ui/redirect.html -new file mode 100755 -index 0000000..59eeb19 ---- /dev/null -+++ b/ui/redirect.html -@@ -0,0 +1,29 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -\ No newline at end of file -diff --git a/ui/viewpost.html b/ui/viewpost.html -new file mode 100644 -index 0000000..5951d47 ---- /dev/null -+++ b/ui/viewpost.html -@@ -0,0 +1,60 @@ -+ -+ -+ -+ -+ -+ -+ Post | {{post.title_post }} -+ -+ -+ {% include "header.html" %} -+





    -+ -+

    Malaria : infoHub

    -+ -+
    -+
    -+

    View Post

    -+
    -+ -+ -+
    -+
    -+
    -+
    -+

    Title :

    -+
    -+
    -+

    {{post.title_post}}

    -+
    -+
    -+
    -+
    -+
    -+
    -+

    Descrpition :

    -+
    -+
    -+

    {{post.description_post}}

    -+
    -+

    -+
    -+      -+ -+
    -+ -+
    -+
    -+ -+ -+ -+ -+

    -+ {% include "footer.html" %} -+ -+ -\ No newline at end of file -diff --git a/webhub/__init__.py b/webhub/__init__.py -new file mode 100644 -index 0000000..e69de29 -diff --git a/webhub/__init__.pyc b/webhub/__init__.pyc -new file mode 100644 -index 0000000..0a6fa88 -Binary files /dev/null and b/webhub/__init__.pyc differ -diff --git a/webhub/admin.py b/webhub/admin.py -new file mode 100644 -index 0000000..6163a44 ---- /dev/null -+++ b/webhub/admin.py -@@ -0,0 +1,14 @@ -+#Version : Phython/Django 2.7.6, PostgreSQL 9.3.4 -+#Author : Vaibhavi Desai -+#Github username : desaivaibhavi -+#email : ranihaileydesai@gmail.com -+ -+ -+from django.contrib import admin -+from webhub.models import Pcuser -+from webhub.models import Post -+ -+admin.site.register(Pcuser) -+admin.site.register(Post) -+ -+# Register your models here. -diff --git a/webhub/admin.pyc b/webhub/admin.pyc -new file mode 100644 -index 0000000..95dc157 -Binary files /dev/null and b/webhub/admin.pyc differ -diff --git a/webhub/checker.py b/webhub/checker.py -new file mode 100755 -index 0000000..531d428 ---- /dev/null -+++ b/webhub/checker.py -@@ -0,0 +1,36 @@ -+#Version : Phython/Django 2.7.6, PostgreSQL 9.3.4 -+#Author : Vaibhavi Desai -+#Github username : desaivaibhavi -+#email : ranihaileydesai@gmail.com -+ -+from django.http import HttpResponse -+from django.utils import timezone -+from webhub.models import * -+from django.views.decorators.csrf import csrf_exempt -+import datetime -+from django.contrib.auth import authenticate, login, logout -+from django.contrib.auth.models import User -+from django.shortcuts import redirect -+from django.db.models import Count, Min, Sum, Avg -+import uuid -+import jinja2 -+from jinja2.ext import loopcontrols -+ -+jinja_environ = jinja2.Environment(loader=jinja2.FileSystemLoader(['ui']), extensions=[loopcontrols]) -+ -+#Checker function used to see if user is logged in and verified etc. Made separately instead of writing repeatedly -+def check(request): -+ -+ #Check if user is logged in -+ if not request.user.is_authenticated(): -+ return HttpResponse(jinja_environ.get_template('index.html').render({"pcuser":None})) -+ -+ #Check if user has an associated rider -+ #(This will be false if the admin logs in) -+ try: -+ request.user.pcuser -+ except: -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'

    No Pcuser associated! Add a pcuser from admin

    '})) -+ -+ return None -diff --git a/webhub/checker.pyc b/webhub/checker.pyc -new file mode 100644 -index 0000000..1f0d17d -Binary files /dev/null and b/webhub/checker.pyc differ -diff --git a/webhub/models.py b/webhub/models.py -new file mode 100644 -index 0000000..b1e78c1 ---- /dev/null -+++ b/webhub/models.py -@@ -0,0 +1,42 @@ -+#Version : Phython/Django 2.7.6, PostgreSQL 9.3.4 -+#Author : Vaibhavi Desai -+#Github username : desaivaibhavi -+#email : ranihaileydesai@gmail.com -+ -+from django.db import models -+from django import forms -+from django.utils import timezone -+from django.contrib.auth.models import User -+import os -+from uuid import uuid4 -+ -+#Django provides a table called user that stores basic user information like username, password and email id. -+ -+class Pcuser(models.Model): -+ #username -+ user = models.OneToOneField(User) -+ #location -+ location = models.CharField(max_length=300) -+ #phone number -+ phone = models.CharField(max_length=150) -+ #gender -+ gender = models.CharField(max_length=10) -+ #for reset_password -+ reset_pass = models.CharField(default="",max_length=320) -+ -+ def __unicode__(self): -+ return self.user.username -+ -+ -+#Post table stores details about posts -+ -+class Post(models.Model): -+ #The owner of the post -+ owner = models.ForeignKey(Pcuser, null=False, related_name='owner') -+ #title -+ title_post = models.CharField(max_length=300) -+ #description -+ description_post = models.CharField(max_length=2000) -+ -+ def __unicode__(self): -+ return self.owner.user.username -\ No newline at end of file -diff --git a/webhub/models.pyc b/webhub/models.pyc -new file mode 100644 -index 0000000..4af902e -Binary files /dev/null and b/webhub/models.pyc differ -diff --git a/webhub/tests.py b/webhub/tests.py -new file mode 100644 -index 0000000..8cece82 ---- /dev/null -+++ b/webhub/tests.py -@@ -0,0 +1,8 @@ -+#Version : Phython/Django 2.7.6, PostgreSQL 9.3.4 -+#Author : Vaibhavi Desai -+#Github username : desaivaibhavi -+#email : ranihaileydesai@gmail.com -+ -+from django.test import TestCase -+ -+# Create your tests here. -diff --git a/webhub/urls.py b/webhub/urls.py -new file mode 100644 -index 0000000..b04ff07 ---- /dev/null -+++ b/webhub/urls.py -@@ -0,0 +1,30 @@ -+#Version : Phython/Django 2.7.6, PostgreSQL 9.3.4 -+#Author : Vaibhavi Desai -+#Github username : desaivaibhavi -+#email : ranihaileydesai@gmail.com -+ -+from django.conf.urls import patterns, url -+ -+from webhub import views -+ -+urlpatterns = patterns('', -+ url(r'^index/$', views.index, name='index'), -+ url(r'^$', views.dashboard, name='dashboard'), -+ url(r'^login_do/$', views.login_do, name='login_do'), -+ url(r'^logout_do/$', views.logout_do, name='logout_do'), -+ url(r'^malaria/$', views.malaria, name='malaria'), -+ url(r'^peacetrack/$', views.peacetrack, name='peacetrack'), -+ url(r'^post_form/$', views.post_form, name='post_form'), -+ url(r'^post_new/$', views.post_new, name='post_new'), -+ url(r'^edit_post/$', views.edit_post, name='edit_post'), -+ url(r'^edit_post_page/$', views.edit_post_page, name='edit_post_page'), -+ url(r'^view_post/$', views.view_post, name='view_post'), -+ url(r'^delete_post/$', views.delete_post, name='delete_post'), -+ url(r'^profile/$', views.profile, name='profile'), -+ url(r'^edit_profile/$', views.edit_profile, name='edit_profile'), -+ url(r'^edit_profile_page/$', views.edit_profile_page, name='edit_profile_page'), -+) -+ -+ -+ -+ -diff --git a/webhub/urls.pyc b/webhub/urls.pyc -new file mode 100644 -index 0000000..f3ecc38 -Binary files /dev/null and b/webhub/urls.pyc differ -diff --git a/webhub/views.py b/webhub/views.py -new file mode 100644 -index 0000000..b952a54 ---- /dev/null -+++ b/webhub/views.py -@@ -0,0 +1,226 @@ -+#Version : Phython/Django 2.7.6, PostgreSQL 9.3.4 -+#Author : Vaibhavi Desai -+#Github username : desaivaibhavi -+#email : ranihaileydesai@gmail.com -+ -+from django.shortcuts import render -+from django.shortcuts import render_to_response -+from django.db import IntegrityError -+from django.http import HttpResponse -+from django.http import HttpResponseRedirect -+from django.contrib import auth -+from django.contrib.auth import authenticate, login, logout -+from django.core.context_processors import csrf -+from django.views.decorators.csrf import csrf_exempt -+import jinja2 -+from jinja2.ext import loopcontrols -+from webhub.checker import check -+from webhub.models import * -+ -+jinja_environ = jinja2.Environment(loader=jinja2.FileSystemLoader(['ui']), extensions=[loopcontrols]) -+ -+#Calls index page -+def index(request): -+ return HttpResponse(jinja_environ.get_template('index.html').render({"pcuser":None})) -+ -+#Calls dashboard wish is shown after a user is logged in -+def dashboard(request): -+ -+ retval = check(request) -+ if retval <> None: -+ return retval -+ -+ template_values = {'pcuser' : request.user.pcuser, -+ } -+ return HttpResponse(jinja_environ.get_template('dashboard.html').render(template_values)) -+ -+ -+#Called when a user clicks login button. -+@csrf_exempt -+def login_do(request): -+ username = request.REQUEST['username'] -+ password = request.REQUEST['password'] -+ user = authenticate(username=username, password=password) -+ -+ if user is not None: -+ if user.is_active: -+ login(request, user) -+ if 'redirect' in request.REQUEST.keys(): -+ return HttpResponse(jinja_environ.get_template('redirect.html').render({"pcuser":None,"redirect_url":request.REQUEST['redirect'].replace("!!__!!","&")})) -+ return HttpResponse(jinja_environ.get_template('redirect.html').render({"pcuser":None,"redirect_url":"/"})) -+ -+ else: -+ # Return an 'invalid login' error message. -+ if "js" in request.REQUEST.keys(): -+ if len(User.objects.filter(username=request.REQUEST['username'])) == 0: -+ return HttpResponse("inv_user") -+ return HttpResponse("inv_pass") -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, -+ "text":'Invalid Login.', "text1":'Click here to go to home page.',"link":'/'})) -+ -+ -+#Called when a user clicks logout button. -+def logout_do(request): -+ logout(request) -+ redirect_url = "/" -+ if 'redirect_url' in request.REQUEST.keys(): -+ redirect_url = request.REQUEST['redirect_url'] -+ return HttpResponse(jinja_environ.get_template('redirect.html').render({"pcuser":None,"redirect_url":redirect_url})) -+ -+ -+#Called when a user goes to malaria track. -+def malaria(request): -+ all_posts = Post.objects.all() -+ return HttpResponse(jinja_environ.get_template('malaria.html').render({"all_posts":all_posts, "pcuser":request.user.pcuser})) -+ -+#called when a user wants to view a particular post. -+def view_post(request): -+ retval = check(request) -+ if retval <> None: -+ return retval -+ -+ try: -+ pcuser=request.user.pcuser -+ key=request.REQUEST['key'] -+ postobj=Post.objects.get(id=key) -+ return HttpResponse(jinja_environ.get_template('viewpost.html').render({"pcuser":request.user.pcuser, 'post':postobj})) -+ except Exception as e: -+ return HttpResponse(e) -+ -+ -+#The call function for new post form. -+def post_form(request): -+ retval = check(request) -+ if retval <> None: -+ return retval -+ return HttpResponse(jinja_environ.get_template('newpost.html').render({"pcuser":request.user.pcuser, 'owner':request.user.pcuser})) -+ -+#Called when a user clicks submit on new post form. -+@csrf_exempt -+def post_new(request): -+ #check for user login -+ retval = check(request) -+ if retval <> None: -+ return retval -+ owner = request.user.pcuser -+ title_post = request.REQUEST['title'] -+ description_post = request.REQUEST['description'] -+ -+ entry = Post(owner=owner, -+ title_post=title_post, -+ description_post=description_post, -+ ) -+ entry.save() -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, -+ "text":'Post successful.',"text1":'Click here to go to home.', -+ "link": '/'})) -+ -+#Calls the edit post page. Also, sends the autofill form data. -+def edit_post_page(request): -+ retval = check(request) -+ if retval <> None: -+ return retval -+ -+ try: -+ pcuser=request.user.pcuser -+ key=request.REQUEST['key'] -+ postobj=Post.objects.get(id=key) -+ return HttpResponse(jinja_environ.get_template('editpost.html').render({"pcuser":request.user.pcuser, 'post':postobj})) -+ except Exception as e: -+ return HttpResponse(e) -+ -+#Called when a user edits his/her post. -+@csrf_exempt -+def edit_post(request): -+ retval = check(request) -+ if retval <> None: -+ return retval -+ -+ owner = request.user.pcuser -+ postid = request.REQUEST['postid'] -+ postobj = None -+ try: -+ postobj = Post.objects.get(pk=postid) -+ except Exception as e: -+ return HttpResponse(e) -+ -+ title_post = request.REQUEST['title'] -+ description_post = request.REQUEST['description'] -+ -+ -+ postobj.title_post = title_post -+ postobj.description_post = description_post -+ -+ postobj.save() -+ -+ postobj.owner.save() -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, -+ "text":'Post edited successfully.',"text1":'Click here to view post.', "link": '/view_post/?key=' + str(postobj.id)})) -+ -+#Called when a user cancels his post. -+@csrf_exempt -+def delete_post(request): -+ retval = check(request) -+ if retval <> None: -+ return retval -+ user = request.user -+ -+ postid = request.REQUEST['postid'] -+ -+ postobj = None -+ try: -+ postobj = Post.objects.get(pk=postid) -+ except Exception as e: -+ return HttpResponse(e) -+ -+ postobj.delete() -+ -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, -+ "text":'Post Deleted successfully.', "text1":'Click here to go to home page.',"link":'/'})) -+ -+#Call to open user's profile page.Sends data to be displayed. -+def profile(request): -+ -+ try: -+ pcuserid = request.REQUEST['id'] -+ if pcuserid == request.user.pcuser.pk: -+ return HttpResponse(jinja_environ.get_template('profile.html').render({"pcuser":request.user.pcuser, "profiler":request.user.pcuser})) -+ else: -+ return HttpResponse(jinja_environ.get_template('profile.html').render({"pcuser":request.user.pcuser, "profiler":Pcuser.objects.get(pk=pcuserid)})) -+ except: -+ return HttpResponse(jinja_environ.get_template('profile.html').render({"pcuser":request.user.pcuser, "profiler":request.user.pcuser})) -+ -+ -+#Calls the edit profile page. The autofill data is sent too. -+def edit_profile_page(request): -+ if not request.user.is_authenticated(): -+ return HttpResponse(jinja_environ.get_template('index.html').render({"pcuser":None})) -+ pcuserid = request.REQUEST['id'] -+ return HttpResponse(jinja_environ.get_template('edit_profile.html').render({"pcuser":Pcuser.objects.get(pk=pcuserid)})) -+ -+#Edit profile function. Called after a user presses done in edit profile. New data is requested from frontend and stored. -+@csrf_exempt -+def edit_profile(request): -+ if not request.user.is_authenticated(): -+ return HttpResponse(jinja_environ.get_template('index.html').render({"pcuser":None})) -+ -+ -+ -+ -+ request.user.pcuser.gender = request.REQUEST['gender'] -+ request.user.pcuser.phone = request.REQUEST['phone'] -+ request.user.pcuser.phone = request.REQUEST['email'] -+ request.user.pcuser.gender = request.REQUEST['location'] -+ request.user.first_name = request.REQUEST['first_name'] -+ request.user.last_name = request.REQUEST['last_name'] -+ -+ request.user.pcuser.save() -+ -+ request.user.save() -+ -+ return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, -+ "text":'Profile edit successful.',"text1":'Click here to view the profile.',"link":'/profile/?id='+ str(request.user.pcuser.id)})) -+ -+#called when user wishes to go to the Peacetrack from dashboard -+def peacetrack(request): -+ return HttpResponse(jinja_environ.get_template('peacetrack.html').render({"pcuser":None})) -\ No newline at end of file -diff --git a/webhub/views.pyc b/webhub/views.pyc -new file mode 100644 -index 0000000..ada3218 -Binary files /dev/null and b/webhub/views.pyc differ diff --git a/code_of_conduct.md b/code_of_conduct.md new file mode 100644 index 00000000..e0dfd11d --- /dev/null +++ b/code_of_conduct.md @@ -0,0 +1,82 @@ +# Code of Conduct + +## 1. Purpose + +A primary goal of Systers is to be inclusive to the largest number of contributors, with the most varied and diverse backgrounds possible. As such, we are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, sexual orientation, ability, ethnicity, socioeconomic status, and religion (or lack thereof). + +This code of conduct outlines our expectations for all those who participate in our community, as well as the consequences for unacceptable behavior. + +We invite all those who participate in Systers to help us create safe and positive experiences for everyone. + +## 2. Open Source Citizenship + +A supplemental goal of this Code of Conduct is to increase open source citizenship by encouraging participants to recognize and strengthen the relationships between our actions and their effects on our community. + +Communities mirror the societies in which they exist and positive action is essential to counteract the many forms of inequality and abuses of power that exist in society. + +If you see someone who is making an extra effort to ensure our community is welcoming, friendly, and encourages all participants to contribute to the fullest extent, we want to know. + +## 3. Expected Behavior + +The following behaviors are expected and requested of all community members: + +* Participate in an authentic and active way. In doing so, you contribute to the health and longevity of this community. +* Exercise consideration and respect in your speech and actions. +* Attempt collaboration before conflict. +* Refrain from demeaning, discriminatory, or harassing behavior and speech. +* Be mindful of your surroundings and of your fellow participants. Alert community leaders if you notice a dangerous situation, someone in distress, or violations of this Code of Conduct, even if they seem inconsequential. +* Remember that community event venues may be shared with members of the public; please be respectful to all patrons of these locations. + +## 4. Unacceptable Behavior + +The following behaviors are considered harassment and are unacceptable within our community: + +* Violence, threats of violence or violent language directed against another person. +* Sexist, racist, homophobic, transphobic, ableist or otherwise discriminatory jokes and language. +* Posting or displaying sexually explicit or violent material. +* Posting or threatening to post other people’s personally identifying information ("doxing"). +* Personal insults, particularly those related to gender, sexual orientation, race, religion, or disability. +* Inappropriate photography or recording. +* Inappropriate physical contact. You should have someone’s consent before touching them. +* Unwelcome sexual attention. This includes, sexualized comments or jokes; inappropriate touching, groping, and unwelcomed sexual advances. +* Deliberate intimidation, stalking or following (online or in person). +* Advocating for, or encouraging, any of the above behavior. +* Sustained disruption of community events, including talks and presentations. + +## 5. Consequences of Unacceptable Behavior + +Unacceptable behavior from any community member, including sponsors and those with decision-making authority, will not be tolerated. + +Anyone asked to stop unacceptable behavior is expected to comply immediately. + +If a community member engages in unacceptable behavior, the community organizers may take any action they deem appropriate, up to and including a temporary ban or permanent expulsion from the community without warning (and without refund in the case of a paid event). + +## 6. Reporting Guidelines +If you are subject to or witness unacceptable behavior, or have any other concerns, please notify a community organizer as soon as possible by emailing systers.keeper@gmail.com. Please read [Reporting Guidelines](reporting_guidelines.md) for details. + + + +Additionally, community organizers are available to help community members engage with local law enforcement or to otherwise help those experiencing unacceptable behavior feel safe. In the context of in-person events, organizers will also provide escorts as desired by the person experiencing distress. + +## 7. Addressing Grievances + +Only permanent resolutions (such as bans) may be appealed. To appeal a decision of the working group, contact the Systers' Open Source Board at os-board@anitab.org with your appeal and the board will review the case. + + +## 8. Scope + +We expect all community participants (contributors, paid or otherwise; sponsors; and other guests) to abide by this Code of Conduct in all community venues–online and in-person–as well as in all one-on-one communications pertaining to community business. + +This code of conduct and its related procedures also applies to unacceptable behavior occurring outside the scope of community activities when such behavior has the potential to adversely affect the safety and well-being of community members. + +## 9. Contact info + +systers.keeper@gmail.com + +## 10. License and attribution + +This Code of Conduct is distributed under a [Creative Commons Attribution-ShareAlike license](http://creativecommons.org/licenses/by-sa/3.0/). + +Portions of text derived from the [Django Code of Conduct](https://www.djangoproject.com/conduct/) and the [Geek Feminism Anti-Harassment Policy](http://geekfeminism.wikia.com/wiki/Conference_anti-harassment/Policy). + +Retrieved on November 22, 2016 from [http://citizencodeofconduct.org/](http://citizencodeofconduct.org/) diff --git a/docs/Contribution.md b/docs/Contribution.md new file mode 100644 index 00000000..db70a700 --- /dev/null +++ b/docs/Contribution.md @@ -0,0 +1,147 @@ +# Contribution Guide + +Thank you for your interest in contributing to Mobile App Control Center, Systers! There are always bugs to file; bugs to fix in the code; improvements to be made to the documentation; and more. + + +The instructions given below are for software developers who want to work on [our current code](https://github.com/systers/macc). + +## What to work on + +1. You can check the [opened issues](https://github.com/systers/macc/issues). They are related to the existing code or for tracking new features. + +2. Claim the issue, after approval, work on it and send a pull request. + +3. Create a new issue, a community member will get back to you and once approved, send a pull request for the same. + +4. All the PRs are needed to be sent to the [develop](https://github.com/systers/macc) branch. + +## Avoid doing the following mistakes +1. Fix a new issue and submit a PR without reporting and getting it approved at first. + +2. Fix an issue assigned to somebody else and submit a PR before the assignee does. + +3. Report issues which are previously reported by others. (Please check the closed issues too before you report an issue). + +4. Suggest completely new developments in the issue list. (Please use the mailing list for this kind of suggestions. Use issue list to suggest bugs/features in the already implemented sections.) + +## Best Practices +### For Issue Reporting +1. Go through the Issue List and see whether the issue you found or any related issue is already reported. + +2. If you don't find the issue you are reporting in issue list, check whether it is reported and closed (present in closed issue list). + +3. If the issue is new, report the issue as a new one with following: + * Screen shot if possible + * Short description for the title + * A detailed description with steps to recreate the issue (for bugs) + * A description of how the issue will improve the application ( for enhancements) + +### For Pull Requests +1. Use meaningful commit messages. + +2. Do not over commit. (Do not include multiple commits for a small change) + +3. Do not add the merge commits to the PR. + +4. Usually use a single commit for a single issue, unless the issues are related or contain a significant code change. + +5. There are certain kind of files you do not add to source control (Like the vitual environment folder). If you already don't know about them, please do a quick search and find them and remove them from your commit. + +6. When sending a PR have an appropriate title referencing the issue which it solves. + +7. If it is a UI change, add a screen shot of the new/fixed UI. + +8. Have a short description on what has gone wrong (like a root cause analysis and description of the fix), if that information is not already present in the issue. + +9. Do not ask us to review it in a separate comment. We will review it anyway. + + +## Coding Style and Standards + +Follow the [PEP8](https://www.python.org/dev/peps/pep-0008/) and [PEP257](https://www.python.org/dev/peps/pep-0257/#multi-line-docstrings) Style Guides. + +Most important things: + + 1. Separate top-level function and class definitions with two blank lines. + + 2. Keep lines shorter than 100 characters when possible (especially at Python code). + + 3. Use whitespace between comma and separate values. + + 4. Give classes CamelCase naming. + + 5. Give functions lowercase namings. + + 6. Refrain from suggesting completely new developments in the issue list. Make you discuss them once in our [slack channel](systers.io/slack-systers-opensource/). + + + +## Git workflow + +When you want to start contributing, you should [follow the instructions](https://github.com/systers/macc/blob/develop/docs/Installation%20Guide.md). After that, follow these steps. + +Set your cloned fork to track upstream changes (changes to the main repository), then fetch and merge from the upstream branch: + + `$ git remote add --track upstream https://github.com/systers/macc.git` + `$ git fetch upstream develop` + `$ git merge upstream/develop` + + +Set up a branch for a particular set of changes and switch to it: + + `$ git checkout -b my_branch` + +It is important that you create a new branch from the default (develop) branch which is the exact copy of the upstream, else you might mix up commits from different branches. So switch to `develop` branch before creating a new one. + +Run `git remote -v` to check the status, you should see something like this: + + > origin https://github.com/YOUR_USERNAME/macc.git (fetch) + + > origin https://github.com/YOUR_USERNAME/macc.git (push) + + > upstream https://github.com/systers/macc.git (fetch) + + > upstream https://github.com/systers/macc/git (push) + +Code! + +Commit the changes. + + `$ git add my_changed_files` + `$ git commit -m "A small but relevant commit message"` + + +When you're done, figure out how many commits you've made: + + `$ git log` + +Push the changes to your forked repository. + + `$ git push origin my_branch` + +Issue a pull request on GitHub. + +Wait to hear from one of the collaborators. + +If you're asked to change your commit message, you can amend the message and commit: + + `$ git commit --amend` + `$ git push -f origin my_branch` + +If you're asked to make changes on your code you can stage them and amend the commit: + + `$ git add my_changed_files` + `$ git commit --amend` + `$ git push -f origin my_branch` + +Avoid doing `$ git add --all` since it also adds the changes needed specifically for your development environment. Manually go through the changes once before you stage them. In case you accidentally stage a file you were not supposed to, you have to unstage all the files again. This can be done by: + + `$ git reset --hard HEAD` + +If you need more references and Git expertise, a good resource is the [Git Book](https://git-scm.com/book/en/v2). + +##Troubleshooting +If there are any other questions or concerns, you can either send a mail to the systers-dev mailing list or join #macc channel in our slack group. To get an invitation to the slack group [click here] (http://systers.io/slack-systers-opensource/). + + + diff --git a/docs/Installation Guide.md b/docs/Installation Guide.md index b41980a5..9e0e16dd 100644 --- a/docs/Installation Guide.md +++ b/docs/Installation Guide.md @@ -4,19 +4,43 @@ This tutorial assumes that the user is installing and running the project under the Ubuntu Virtual Machine that is provided by PeaceCorps. ## Table of Contents -1. [Install git](https://github.com/Nerdylicious/app-web-server/blob/master/docs/Installation%20Guide.md#install-git) -2. [Clone Project](https://github.com/Nerdylicious/app-web-server/blob/master/docs/Installation%20Guide.md#clone-project) -3. [Install Django and PostgreSQL](https://github.com/Nerdylicious/app-web-server/blob/master/docs/Installation%20Guide.md#install-django-and-postgresql) -4. [Install VirtualBox and Vagrant](https://github.com/Nerdylicious/app-web-server/blob/master/docs/Installation%20Guide.md#install-virtualbox-and-vagrant) -5. [Download PeaceCorps Ubuntu Virtual Machine](https://github.com/Nerdylicious/app-web-server/blob/master/docs/Installation%20Guide.md#download-peacecorps-ubuntu-virtual-machine) -6. [Using Vagrant](https://github.com/Nerdylicious/app-web-server/blob/master/docs/Installation%20Guide.md#using-vagrant) -7. [Install Project Dependencies](https://github.com/Nerdylicious/app-web-server/blob/master/docs/Installation%20Guide.md#install-project-dependencies) -8. [Setup PostgreSQL](https://github.com/Nerdylicious/app-web-server/blob/master/docs/Installation%20Guide.md#setup-postgresql) -9. [Update settings.py](https://github.com/Nerdylicious/app-web-server/blob/master/docs/Installation%20Guide.md#update-settingspy) -10. [Generate Database Tables Corresponding to Django Models](https://github.com/Nerdylicious/app-web-server/blob/master/docs/Installation%20Guide.md#generate-database-tables-corresponding-to-django-models) -11. [Run Development Server](https://github.com/Nerdylicious/app-web-server/blob/master/docs/Installation%20Guide.md#run-development-server) -12. [Try out Mobile App Control Center](https://github.com/Nerdylicious/app-web-server/blob/master/docs/Installation%20Guide.md#try-out-mobile-app-control-center) -13. [Exit the Virtual Machine](https://github.com/Nerdylicious/app-web-server/blob/master/docs/Installation%20Guide.md#exit-the-virtual-machine) +1. [Install Python3.6](https://github.com/systers/macc/blob/develop/docs/Installation%20Guide.md#install-python3.6) +2. [Install git](https://github.com/systers/macc/blob/develop/docs/Installation%20Guide.md#install-git) +3. [Clone Project](https://github.com/systers/macc/blob/develop/docs/Installation%20Guide.md#clone-project) +4. [Install Django and PostgreSQL](https://github.com/systers/macc/blob/develop/docs/Installation%20Guide.md#install-django-and-postgresql) +5. [Install VirtualBox and Vagrant](https://github.com/systers/macc/blob/develop/docs/Installation%20Guide.md#install-virtualbox-and-vagrant) +6. [Download PeaceCorps Ubuntu Virtual Machine](https://github.com/systers/macc/blob/develop/docs/Installation%20Guide.md#download-peacecorps-ubuntu-virtual-machine) +7. [Using Vagrant](https://github.com/systers/macc/blob/develop/docs/Installation%20Guide.md#using-vagrant) +8. [Install Project Dependencies](https://github.com/systers/macc/blob/develop/docs/Installation%20Guide.md#install-project-dependencies) +9. [Setup PostgreSQL](https://github.com/systers/macc/blob/develop/docs/Installation%20Guide.md#setup-postgresql) +10. [Update settings.py](https://github.com/systers/macc/blob/develop/docs/Installation%20Guide.md#update-settingspy) +11. [Generate Database Tables Corresponding to Django Models](https://github.com/systers/macc/blob/develop/docs/Installation%20Guide.md#generate-database-tables-corresponding-to-django-models) +12. [Run Development Server](https://github.com/systers/macc/blob/develop/docs/Installation%20Guide.md#run-development-server) +13. [Try out Mobile App Control Center](https://github.com/systers/macc/blob/develop/docs/Installation%20Guide.md#try-out-mobile-app-control-center) +14. [Exit the Virtual Machine](https://github.com/systers/macc/blob/develop/docs/Installation%20Guide.md#exit-the-virtual-machine) + +## Install Python3.6 + +By default, your PC has Python 2.7 installed. To install Python 3.6, follow the steps below: + +To install some build dependencies: + + sudo apt install build-essential checkinstall + sudo apt install libreadline-gplv2-dev libncursesw5-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev + +Then, download Python 3.6 source code from python.org by the following command: + + wget https://www.python.org/ftp/python/3.6.0/Python-3.6.0.tar.xz + +Next, we extract the tarball: + + tar xvf Python-3.6.0.tar.xz + +Now change directory into the source directory, configure the build environment and install: + + cd Python-3.6.0/ + ./configure + sudo make install ## Install git @@ -28,18 +52,21 @@ Clone the project from GitHub by running the following command: git clone project_url_here -For my project, this would correspond to: +For our project, this would correspond to: - git clone git@github.com:Nerdylicious/app-web-server.git + git clone https://github.com/systers/macc.git ## Install Django and PostgreSQL If you are installing and running the project on your local machine and not on the PeaceCorps VM, then you will need to download and install the following software: -1. [Django](https://www.djangoproject.com/download/) (version >= 1.6.5) -2. [PostgreSQL](http://www.postgresql.org/download/) (version >= 9.3.4) +1. [Django](https://www.djangoproject.com/download/) (version == 1.11) +2. [PostgreSQL](http://www.postgresql.org/download/) (version >= 9.5.5, version 9.6 preferred) + +Skip the next two sections if not using the PeaceCorps VM and jump to the section '**Install Project Dependencies**'. -**Skip this step if you are installing and running the project on the PeaceCorps VM, as Django and PostgreSQL are already included in the PeaceCorps VM.** + +**Skip this section if you are installing and running the project on the PeaceCorps VM, as Django and PostgreSQL are already included in the PeaceCorps VM.** ## Install VirtualBox and Vagrant @@ -54,7 +81,7 @@ Install VirtualBox and Vagrant by running the installers. ## Download PeaceCorps Ubuntu Virtual Machine -A Vagrant file is located in the top level directory for the project (at [https://github.com/Nerdylicious/app-web-server/blob/master/Vagrantfile](https://github.com/Nerdylicious/app-web-server/blob/master/Vagrantfile) found on GitHub. In case you do not have a copy of this Vagrant file, here are it's contents: +A Vagrant file is located in the [top level directory for the project.](https://github.com/systers/macc/blob/develop/Vagrantfile) found on GitHub. In case you do not have a copy of this Vagrant file, here are it's contents: ``` # -*- mode: ruby -*- # vi: set ft=ruby : @@ -118,27 +145,56 @@ On the VM, update and upgrade: Install project dependencies: - sudo apt-get install python-dev - sudo apt-get install python-psycopg2 + sudo apt-get install python3-dev + sudo apt-get install python3-psycopg2 sudo apt-get install libpq-dev - sudo apt-get install python-pip - -Install all Python dependencies specified in the [requirements.txt](https://github.com/Nerdylicious/app-web-server/blob/master/requirements.txt) file using pip: - - sudo pip install Django==1.6.5 - sudo pip install Jinja2==2.7.3 - sudo pip install MarkupSafe==0.23 - sudo pip install Pillow==2.5.1 - sudo pip install dj-database-url==0.3.0 - sudo pip install dj-static==0.0.6 - sudo pip install django-toolbelt==0.0.1 - sudo pip install djangorestframework==2.3.14 - sudo pip install gunicorn==19.1.0 - sudo pip install psycopg2==2.5.3 - sudo pip install static3==0.5.1 - sudo pip install django-rest-swagger==0.3.2 - sudo pip install PyYAML==3.11 - + sudo apt-get install python3-pip + +Install Python's Virtual Environment (**Only for users not using Peacecorp's VM**) + + sudo pip3 install virtualenv + +Create Python's Virtual Environment (**Only for users not using Peacecorp's VM**), by moving to the top level directory of the project containing **manage.py** and create your virtual environment, type : + + virtualenv venv + +Activate Python's Virtual Environment (**Only for users not using Peacecorp's VM**) + + source venv/bin/activate + +Now, your prompt will change to indicate that you are now operating within the virtual environment. It will look something like this (venv)user@host:~/myproject$. + +**From here on the process is same whether using Peacecorp's VM or not** + +Install all Python dependencies specified in the [requirements.txt](https://github.com/systers/app-web-server/blob/develop/requirements.txt) file using pip: + + sudo pip3 install -r requirements.txt + +Or install one by one + + sudo pip3 install Django==1.11 + sudo pip3 install Jinja2==2.9.6 + sudo pip3 install MarkupSafe==1.0 + sudo pip3 install Pillow==4.1.1 + sudo pip3 install dj-database-url==0.4.2 + sudo pip3 install dj-static==0.0.6 + sudo pip3 install django-toolbelt==0.0.1 + sudo pip3 install djangorestframework==3.6.3 + sudo pip3 install gunicorn==19.7.1 + sudo pip3 install psycopg2==2.7.1 + sudo pip3 install static3==0.7.0 + sudo pip3 install django-rest-swagger==2.1.2 + sudo pip3 install PyYAML==3.12 + +**Configure autoenv** + + sudo pip3 install autoenv + echo "source `which activate.sh`" >> ~/.bashrc + +Changing Directory to the cloned directory will automatically resolve export settings error + + cd macc (cloned directory) + ## Setup PostgreSQL We will now setup PostgreSQL by first running the postgres client as root: @@ -223,28 +279,32 @@ EMAIL_HOST_USER = 'pc.mobile.control.center.com' EMAIL_HOST_PASSWORD = 'alphadeltaepsilon' EMAIL_PORT = 465 ``` -Comment out the following lines like so: +The following lines need to be commented or kept as such if already commented: ``` #import dj_database_url -#DATABASES['default'] = dj_database_url.config() +#DATABASES['default'] = dj_database_url.config() ``` ## Generate Database Tables Corresponding to Django Models Change directory to where you can find the **manage.py** file (this is located in the top level directory for the project). If you are installing the project on the VM, the project will be located within the **/vagrant** directory. -To view the sql commands that will be generated from `syncdb`, run the command: +To view the sql commands that will be generated from `migrate`, run the command: - python manage.py sqlall app_name_here + python3 manage.py sqlmigrate app_name_here migration_name + +For example, + + python3 manage.py sqlmigrate malaria_web 0001_initial To generate the database tables that correspond to the Django models, run the command: - python manage.py syncdb + python3 manage.py makemigrations malaria_web malaria_api webhub signup profiles pcsa pcsa_GHN pcsa_safety_tools social_django + python3 manage.py migrate -After running the `syncdb` command, you should get the following prompt. Type in `yes`: +After running the `migrate` command, you should run the following command to create a superuser: - You just installed Djano's auth system, which means you don't have any superusers defined. - Would you like to create one now? (yes/no): yes + python3 manage.py createsuperuser Create a superuser with the following credentials (for now): ``` @@ -252,6 +312,13 @@ Username: admin Email: your email Password: mypassword ``` + +If the models are updated in any way, you need to delete the database and then migrating the fields once more. This can be done by: + + python3 manage.py flush + python3 manage.py makemigrations + python3 manage.py migrate + Check that the tables were created by starting the postgres client and viewing the tables using the `\dt` command. ``` psql -U myuser -d webapp -h localhost -W @@ -269,18 +336,18 @@ Change directory to where you can find the **manage.py** file (this is located i Start the development server by running the command (this runs the development server on the VM): - python manage.py runserver [::]:8000 + python3 manage.py runserver [::]:8000 ## Try out Mobile App Control Center -You can now try out the project by going to [http://localhost:8001](http://localhost:8001) on a browser on your local machine. +You can now try out the project by going to [http://localhost:8000](http://localhost:8000) on a browser on your local machine. Try logging in with your superuser credentials. After clicking on `Submit` you will get the following message: No Pcuser associated! Add a pcuser from admin -We need to create a pcuser that is associated with the superuser we created previously. To do this, go to the Django admin panel at [http://localhost:8001/admin](http://localhost:8001/admin) on your browser. +We need to create a pcuser that is associated with the superuser we created previously. To do this, go to the Django admin panel at [http://localhost:8000/admin](http://localhost:8000/admin) on your browser. On the Django admin login page, login with your superuser credentials. @@ -293,12 +360,11 @@ Location: Your location Phone: Your phone number Gender: Your gender Reset pass: 1 (not sure what this field does) -Imageobj: Pick any random image from your computer Verified: 1 (not sure what this field does) ``` Click on `Save` and logout. -Go back to [http://localhost:8001](http://localhost:8001) +Go back to [http://localhost:8000](http://localhost:8000) Login again with your superuser credentials, it should work since we have associated our superuser with a pcuser. You are now free to try out the application. diff --git a/docs/Installation Guidelines b/docs/Installation Guidelines deleted file mode 100644 index 4e28fe7b..00000000 --- a/docs/Installation Guidelines +++ /dev/null @@ -1,37 +0,0 @@ -Readme file : - -Details about the folders - -infohub : contains the python environment setup, it contains 4 files - init.py, settings.py, urls.py and wsgi.py -settings.py has the main configuration settings like dependencies, database, timezone etc. - -ui : contains the ui page templates of the site, it conains the html,css, js page templates with applied jinja integration. Also, I have used bootstrap for responsiveness and better UI design. - -webhub : contains the python-django backend of the site, it conains 7 files - init.py, admin.py, checker.py, models.py, tests.py, urls.py and views.py -admin.py contains the models that are to be added in the admin panel -checker.py has a check function that redirects the user to the home page depending upon his current status (i.e. login/logout) -models.py has all the information about the models we are going to have in the database -urls.py has the urls of the pages created connected with the respective views -views.py has all the views, ie function to call different views and render the respective values from the backend - -manage.py : is the file that is used to run the application - - -Guidelines to run the application : - -I had to reinstall postgres and python on the VM provided. Also, I had to install python-psycopg2 and jinja on the VM. Make sure the internet is working as I have used some online resources right now. - -To run the application, -1. Start the VM. Install the mentioned dependencies if required -2. Go to the directory which has manage.py file -3. Syncing with the database : run the following command from the terminal - python manage.py syncdb -4. You might be asked to create a super user. Create one. -5. Runnning the server : run the following command from the terminal - python manage.py runserver 0.0.0.0:8000 -6. Open the web-browser and go to http://192.168.33.10:8000/admin. Log in (with the superuser credentials). -7. You will have to create one user from the admin panel.Create one user and add it to the new pcuser. Log out. -8. Now go to http://192.168.33.10:8000/. Login with the credential of the pcuser that you created from the admin panel. -9. Done ! - - diff --git a/docs/Readme.pdf b/docs/Readme.pdf deleted file mode 100644 index 0e7b2ae9..00000000 Binary files a/docs/Readme.pdf and /dev/null differ diff --git a/docs/Update Schema Guide.md b/docs/Update Schema Guide.md new file mode 100644 index 00000000..6237a71d --- /dev/null +++ b/docs/Update Schema Guide.md @@ -0,0 +1,98 @@ +# Update Schema Guide + +## Introduction + +Follow this guide if you have made changes to the database schema and you want the changes to be reflected in your PostgreSQL database. + +All commands are to be run on the machine where the application has been installed. + +If you installed the application on a VM, start up the VM and run the following commands on the VM. + +This guide assumes that the project is running on Django version **1.6.x**. If you are using Django version **1.7** and above, then you may use the built-in database migration tool (see below). + +**Warning**: The instructions below will drop the current `webapp` database and all information stored in this database will be lost. + +## Login to PostgreSQL Client + + psql -U myuser -d postgres -h localhost -W + +You will be prompted to enter a password. If you followed **Installation Guide.md** to install the application, the default password is `mypassword`. + +You can list PostgreSQL databases by running the following command: + + \l + +We will be dropping the `webapp` database. + +## Drop Database + +Drop the `webapp` database by running the following command: + + drop database webapp; + +If you list PostreSQL databases again, you should **not** see the `webapp` database in this list. + + \l + +Exit the PostgreSQL client by running the following command: + + \q + +## Create `webapp` Database + +Create a database called `webapp` by running the following command: + + createdb -U myuser webapp + +You will be prompted to enter a password. If you followed **Installation Guide.md** to install the application, the default password is `mypassword`. + +## Generate Database Tables + +Change directory to where `manage.py` is located. + +To view the sql commands that will be generated from `syncdb`, run the command: + + python manage.py sqlall app_name_here + +Then run the following command to create database tables that correspond to the Django models of the project: + + python manage.py syncdb + +After running the syncdb command, you should get the following prompt. Type in `yes`: + + You just installed Djano's auth system, which means you don't have any superusers defined. + Would you like to create one now? (yes/no): yes + +Create a superuser with the following credentials (for now): + + Username: admin + Email: your email + Password: mypassword + +## Verify Creation of Database Tables + +Check that the tables were created by starting the PostgreSQL client: + + psql -U myuser -d webapp -h localhost -W + +You can view database tables by running the following command: + + \dt + +Make sure to exit the PostgreSQL client before proceeding to the next steps: + + \q + +**You have now updated the database schema!** + +For additional instructions on starting the development server and trying out the application on your browser, please refer to the instructions in **Installation Guide.md** + +## Update Django REST API Serializers + +If you made changes to the database models related to the API (such as adding a new model field/database column), then you may need to update the corresponding serializers found in **serializers.py** in your app directory. + +## Upgrading to Django 1.7 or above + +Django 1.7 introduced built-in database migration support. After this project has been ported to Django 1.7 or above, the built-in migration tool can be used instead. + +[https://docs.djangoproject.com/en/dev/releases/1.7/#schema-migrations](https://docs.djangoproject.com/en/dev/releases/1.7/#schema-migrations) diff --git a/firstaide/__init__.py b/firstaide/__init__.py new file mode 100644 index 00000000..e190cb26 --- /dev/null +++ b/firstaide/__init__.py @@ -0,0 +1,3 @@ + +"""Set app configuration by calling function""" +default_app_config = "firstaide.apps.FirstaideConfig" \ No newline at end of file diff --git a/firstaide/admin.py b/firstaide/admin.py new file mode 100644 index 00000000..3fcf7970 --- /dev/null +++ b/firstaide/admin.py @@ -0,0 +1,7 @@ +from django.contrib import admin +from .models import * + +# Register your models here. +admin.site.register(FirstAideAPI) + + diff --git a/firstaide/apps.py b/firstaide/apps.py new file mode 100644 index 00000000..2498d5f8 --- /dev/null +++ b/firstaide/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + +"""Function to give alias name to firstaide app""" +class FirstaideConfig(AppConfig): + name = 'firstaide' + verbose_name = "FirstAide APIs" diff --git a/firstaide/forms.py b/firstaide/forms.py new file mode 100644 index 00000000..9fc67e2d --- /dev/null +++ b/firstaide/forms.py @@ -0,0 +1,10 @@ +from django.forms import ModelForm +from firstaide.models import * + +class FirstAideAPIForm(ModelForm): + # Forms convert model fields to HTML fields + class Meta: + model = FirstAideAPI + # List of fields to be available in HTML + fields = ['post_id','page_type','title','card_content'] + diff --git a/firstaide/models.py b/firstaide/models.py new file mode 100644 index 00000000..ae29b74d --- /dev/null +++ b/firstaide/models.py @@ -0,0 +1,57 @@ +from django.db import models + +class FirstAideAPI(models.Model): + + # Defining variables for creating choices for post_id field + ADDED_SOON='added-soon' + SEEKING_STAFF_SUPPORT='seeking-staff-support' + SERVICES_AFTER_ASSAULT='services-after-assault' + PEACE_CORPS_COMMITMENT='peace-corps-commitment' + CONFIDENTIALITY='confidentiality' + RADAR='radar' + SEXUAL_PREDATORS='sexual-predators' + SAFETY_PLAN_BASICS='safety-plan-basics' + UNWANTED_ATTENTION='unwanted-attention' + BYSTANDER_INTERVENTION='bystander-intervention' + COMMON_QUESTIONS='common-questions' + SAFETY_PLAN_WORKSHEET='safety-plan-worksheet' + SEXUAL_ASSAULT='sexual-assault' + SEXUAL_ASSAULT_MORE='sexual-assault-more' + GLOSSARY='glossary' + POLICY_SUMMARY='policy-summary' + FURTHER_RESOURCES='further-resources' + IMPACT_OF_ASSAULT='impact-of-assault' + HELP_A_FRIEND='help-a-friend' + MYTHBUSTERS='mythbusters' + SEXUAL_HARRASMENT='sexual-harassment' + + # Choices attribute requires a tuple + POST_ID_CHOICES=((ADDED_SOON, 'added-soon'),(SEEKING_STAFF_SUPPORT, 'seeking-staff-support'),(SERVICES_AFTER_ASSAULT,'services-after-assault'), + (PEACE_CORPS_COMMITMENT,'peace-corps-commitment'),(CONFIDENTIALITY,'confidentiality'),(RADAR,'radar'),(SEXUAL_PREDATORS, 'sexual-predators'), + (SAFETY_PLAN_BASICS, 'safety-plan-basics' ),(UNWANTED_ATTENTION,'unwanted-attention'),(BYSTANDER_INTERVENTION, 'bystander-intervention'),(COMMON_QUESTIONS,'common-questions'), + (SAFETY_PLAN_WORKSHEET,'safety-plan-worksheet'),(SEXUAL_ASSAULT,'sexual-assault'),(SEXUAL_ASSAULT_MORE,'sexual-assault-more'),(GLOSSARY,'glossary'), + (POLICY_SUMMARY,'policy-summary'),(FURTHER_RESOURCES,'further-resources'),(IMPACT_OF_ASSAULT,'impact-of-assault'),(HELP_A_FRIEND,'help-a-friend'),(MYTHBUSTERS,'mythbusters'), + (SEXUAL_HARRASMENT,'sexual-harassment')) + + post_id = models.CharField(max_length=30, choices= POST_ID_CHOICES) + + # Defining variables for creating choices for page_type field + FULL_PAGE_CARD='full_page_card' + MULTI_CARDS_PAGE='multi_cards_page' + MULTI_SEGMENT_PAGE='multi_segment_page' + MULTI_SEGMENT_VERTICAL_PAGE='multi_segment_vertical_page' + + TYPE_OF_PAGE_CATEGORY=((FULL_PAGE_CARD,'full_page_card'),(MULTI_CARDS_PAGE,'multi_cards_page'),( MULTI_SEGMENT_PAGE,'multi_segment_page'),(MULTI_SEGMENT_VERTICAL_PAGE, 'multi_segment_vertical_page')) + + page_type = models.CharField(max_length= 30, choices=TYPE_OF_PAGE_CATEGORY) + title = models.CharField(max_length=200, null = False) + card_content = models.CharField(max_length= 5000, null= False) + + # Name to be shown for a particular instance of this type of model + def __str__(self): + return self.title + + # Name to be shown on the home page of the admin view for the collective set of model instances + class Meta: + verbose_name = 'First Aide API' + diff --git a/firstaide/serializers.py b/firstaide/serializers.py new file mode 100644 index 00000000..9c1abb17 --- /dev/null +++ b/firstaide/serializers.py @@ -0,0 +1,11 @@ +from rest_framework import serializers + +from .models import * + + +class firstAideAPISerializer(serializers.ModelSerializer): + # Serializers convert python objects to serialized form such as JSON or text + class Meta: + model = FirstAideAPI + # List of fields in above model to be serialized + fields = ('card_content',) diff --git a/malaria/__init__.py b/firstaide/services.py similarity index 100% rename from malaria/__init__.py rename to firstaide/services.py diff --git a/firstaide/tests.py b/firstaide/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/firstaide/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/firstaide/urls.py b/firstaide/urls.py new file mode 100644 index 00000000..50c16c99 --- /dev/null +++ b/firstaide/urls.py @@ -0,0 +1,34 @@ +from django.conf.urls import url +from .views import * + +# Connect URLs to Views here +urlpatterns = [ + url(r'^$', + ListFirstAideAPIView.as_view(), + name = 'first_aide_api_home'), + + url(r'^create/$', + CreateFirstAideAPIView.as_view(), + name='first_aide_api_create'), + + url(r'^delete_post/(?P\d+)$', + DeleteFirstAideAPIView.as_view(), + name='first_aide_api_delete_post'), + + url(r'^edit_post/(?P\d+)$', + UpdateFirstAideAPIView.as_view(), + name='first_aide_api_edit_post'), + + url(r'^view_post/(?P\d+)$', + ViewFirstAideAPIView.as_view(), + name='first_aide_api_view_post'), + +] + +""" + (?P\d+ explained - + In Python regular expressions, the syntax for named regular-expression groups is + (?Ppattern), where name is the name of the group and pattern is some pattern to match. + Here pattern is d+ (decimal digits 1 or more eg 0, 11 , 463). Hence, ?P5 will render value of pk as 5 + +""" \ No newline at end of file diff --git a/firstaide/views.py b/firstaide/views.py new file mode 100644 index 00000000..8ccf6a41 --- /dev/null +++ b/firstaide/views.py @@ -0,0 +1,111 @@ +from django.shortcuts import render + +from .forms import * +from .models import * +from rest_framework import viewsets +from django.http import * +from .serializers import * +from rest_framework.response import Response +from django.views.generic import ListView, UpdateView, CreateView, DeleteView, DetailView +from django.contrib.auth.mixins import LoginRequiredMixin + +# Create your views here. + +# View to render the JSON +class FirstAideAPIViewSet(viewsets.ReadOnlyModelViewSet): + + serializer_class = firstAideAPISerializer + page_id="" + page_type="" + title="" + + # When you set queryset (model = xyz), the queryset is created only once, when you start your server. + # On the other hand, the get_queryset method is called for every request. + def get_queryset(self): + # Get all model instances with a particular 'id' + queryset = FirstAideAPI.objects.all().filter(post_id=self.kwargs['id']) + # Get the page_id of the first instance (all instances with a particular id will have the same value for this field) + FirstAideAPIViewSet.page_id = queryset.values_list('post_id',flat=True)[0] + # Get the page_type of the first instance (all instances with a particular id will have the same value for this field) + FirstAideAPIViewSet.page_type = queryset.values_list('page_type',flat=True)[0] + # Get the title of the first instance (all instances with a particular id will have the same value for this field) + FirstAideAPIViewSet.title= queryset.values_list('title',flat=True)[0] + return queryset + + def list(self, request, *args, **kwargs): + instance = self.filter_queryset(self.get_queryset()) + page = self.paginate_queryset(instance) + if page is not None: + serializer = self.get_pagination_serializer(page) + else: + serializer = self.get_serializer(instance, many=True) + + # Create the JSON to be rendered + serializer_data = {"page_id": FirstAideAPIViewSet.page_id,"page_type":FirstAideAPIViewSet.page_type,"title":FirstAideAPIViewSet.title} + # Append the JSON with the card content + serializer_data .update({"content": {"cards":serializer.data}}) + return Response(serializer_data) + +#View to list the cards +class ListFirstAideAPIView(LoginRequiredMixin, ListView): + + model = FirstAideAPI + + # HTML Template rendering the form + template_name = 'firstaide/home.html' + redirect_field_name = 'redirect_to' + + def get_context_data(self, **kwargs): + context = super(ListFirstAideAPIView, self).get_context_data(**kwargs) + # Get model instances sorted by their post_ids + context['post_list'] = FirstAideAPI.objects.all().order_by('post_id') + return context + +# View to add a card +class CreateFirstAideAPIView(LoginRequiredMixin, CreateView): + + model = FirstAideAPI + form_class = FirstAideAPIForm + # HTML Template rendering the form + template_name = 'firstaide/create_post.html' + # URL to be visited after successfully creating a model instance + success_url='/firstaide/' + redirect_field_name = 'redirect_to' + + def form_valid(self, form): + form.instance.owner = self.request.user.pcuser + return super(CreateFirstAideAPIView, self).form_valid(form) + +# View to edit a card +class UpdateFirstAideAPIView(LoginRequiredMixin, UpdateView): + + model = FirstAideAPI + form_class = FirstAideAPIForm + # HTML Template rendering the form + template_name = "firstaide/edit_post.html" + # URL to be visited after successfully updating a model instance + success_url='/firstaide/' + redirect_field_name = 'redirect_to' + + def form_valid(self, form): + form.instance.owner = self.request.user.pcuser + return super(UpdateFirstAideAPIView, self).form_valid(form) + + +# View to delete a card +class DeleteFirstAideAPIView(LoginRequiredMixin, DeleteView): + + model = FirstAideAPI + # HTML Template rendering the form + template_name = "firstaide/delete_post.html" + # URL to be visited after successfully deleting a model instance + success_url = '/firstaide/' + redirect_field_name = 'redirect_to' + + +# View to view a single card +class ViewFirstAideAPIView(LoginRequiredMixin, DetailView): + model = FirstAideAPI + # HTML Template rendering the form + template_name = "firstaide/view_post.html" + redirect_field_name = 'redirect_to' diff --git a/infohub/config.py b/infohub/config.py new file mode 100644 index 00000000..d2ea6164 --- /dev/null +++ b/infohub/config.py @@ -0,0 +1,8 @@ +SOCIAL_AUTH_TWITTER_KEY = 'AjLIz913Xk5gXFEx7ErAyHFrJ' +SOCIAL_AUTH_TWITTER_SECRET = '50Hyxds06GZIT3JEfh5KEQXavphbH9gYdSbH0UO8tTg9eMLMyv' + +SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = '856425658206-uulba4lm3oe2lc1pldl72aoh1lb20fdt.apps.googleusercontent.com' +SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = 'FRf74dTfIG620ESyq_LvYhWU' + +SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/home/' +SOCIAL_AUTH_LOGIN_URL = '/' \ No newline at end of file diff --git a/infohub/settings.py b/infohub/settings.py index 26d28508..55957897 100644 --- a/infohub/settings.py +++ b/infohub/settings.py @@ -1,6 +1,8 @@ import os -BASE_DIR = os.path.dirname(os.path.dirname(__file__)) +from infohub.config import * +BASE_DIR = os.path.dirname(os.path.dirname(__file__)) +SITE_ID = 1 # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/ @@ -11,9 +13,27 @@ # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -TEMPLATE_DEBUG = True - -TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'templates')] +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(BASE_DIR,'templates')], + 'APP_DIRS': True, + 'OPTIONS': { + 'debug': DEBUG, + }, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + + 'social_django.context_processors.backends', # <-- + 'social_django.context_processors.login_redirect', # <-- + ], + }, + + },] # ALLOWED_HOSTS = ['0.0.0.0','localhost','192.168.33.10','192.168.33.10:8000'] @@ -29,9 +49,21 @@ 'rest_framework', 'rest_framework_swagger', 'infohub', - 'malaria', - 'peacetrack', + 'malaria_web', + 'malaria_api', 'webhub', + 'profiles', + 'pcsa', + 'pcsa_GHN', + 'pcsa_safety_tools', + 'allauth', + 'allauth.account', + 'allauth.socialaccount', + 'django.contrib.sites', + 'social_django', + 'firstaide', + 'django_wysiwyg', + 'ckeditor', ) MIDDLEWARE_CLASSES = ( @@ -41,6 +73,17 @@ 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'social_django.middleware.SocialAuthExceptionMiddleware', +) + +AUTHENTICATION_BACKENDS = ( + 'social_core.backends.github.GithubOAuth2', + 'social_core.backends.twitter.TwitterOAuth', + 'social_core.backends.facebook.FacebookOAuth2', + 'social_core.backends.google.GoogleOAuth2', + + 'django.contrib.auth.backends.ModelBackend', + "allauth.account.auth_backends.AuthenticationBackend" ) ROOT_URLCONF = 'infohub.urls' @@ -83,10 +126,9 @@ # Additional locations of static files STATICFILES_DIRS = ( - '/vagrant/submit/media/propics/', - '/vagrant/submit/app-web-server/ui/bootstrap/fonts', - 'lol', + os.path.join(BASE_DIR,'static'), ) + STATICFILES_FINDERS = ( 'django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder', @@ -107,8 +149,7 @@ # Allow all host headers ALLOWED_HOSTS = ['*'] - -# settings for smtp +# SMTP Settings EMAIL_USE_TLS = True DEFAULT_FROM_EMAIL = 'pc.mobile.control.center@gmail.com' SERVER_EMAIL = 'pc.mobile.control.center@gmail.com' @@ -120,3 +161,24 @@ SWAGGER_SETTINGS = { 'is_authenticated': True, } + +DJANGO_WYSIWYG_FLAVOR = "ckeditor" + + +# Django allauth configurations + +# AUTHENTICATION_BACKENDS = ( +# # Needed to login by username in Django admin, regardless of `allauth` +# "django.contrib.auth.backends.ModelBackend", +# # `allauth` specific authentication methods, such as login by e-mail +# "allauth.account.auth_backends.AuthenticationBackend" +# ) + +# To redirect to root page when login is required +LOGIN_REDIRECT_URL = '/' + +# Logout from the account when password is changed +ACCOUNT_LOGOUT_ON_PASSWORD_CHANGE = True + +# Email not verified yet since there is a two step authentication used in the email for sending Authentication messages +ACCOUNT_EMAIL_VERIFICATION ="none" diff --git a/infohub/static/infohub/bootstrap/css/bootstrap-theme.css.map b/infohub/static/infohub/bootstrap/css/bootstrap-theme.css.map deleted file mode 100644 index b36fc9a4..00000000 --- a/infohub/static/infohub/bootstrap/css/bootstrap-theme.css.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["less/theme.less","less/mixins.less"],"names":[],"mappings":"AAeA;AACA;AACA;AACA;AACA;AACA;EACE,wCAAA;ECoGA,2FAAA;EACQ,mFAAA;;ADhGR,YAAC;AAAD,YAAC;AAAD,YAAC;AAAD,SAAC;AAAD,YAAC;AAAD,WAAC;AACD,YAAC;AAAD,YAAC;AAAD,YAAC;AAAD,SAAC;AAAD,YAAC;AAAD,WAAC;EC8FD,wDAAA;EACQ,gDAAA;;ADnER,IAAC;AACD,IAAC;EACC,sBAAA;;AAKJ;EC4PI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;EAyB2C,yBAAA;EAA2B,kBAAA;;AAvBtE,YAAC;AACD,YAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,YAAC;AACD,YAAC;EACC,yBAAA;EACA,qBAAA;;AAeJ;EC2PI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;;AAEA,YAAC;AACD,YAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,YAAC;AACD,YAAC;EACC,yBAAA;EACA,qBAAA;;AAgBJ;EC0PI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;;AAEA,YAAC;AACD,YAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,YAAC;AACD,YAAC;EACC,yBAAA;EACA,qBAAA;;AAiBJ;ECyPI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;;AAEA,SAAC;AACD,SAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,SAAC;AACD,SAAC;EACC,yBAAA;EACA,qBAAA;;AAkBJ;ECwPI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;;AAEA,YAAC;AACD,YAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,YAAC;AACD,YAAC;EACC,yBAAA;EACA,qBAAA;;AAmBJ;ECuPI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;;AAEA,WAAC;AACD,WAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,WAAC;AACD,WAAC;EACC,yBAAA;EACA,qBAAA;;AA2BJ;AACA;EC6CE,kDAAA;EACQ,0CAAA;;ADpCV,cAAe,KAAK,IAAG;AACvB,cAAe,KAAK,IAAG;ECmOnB,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;EDpOF,yBAAA;;AAEF,cAAe,UAAU;AACzB,cAAe,UAAU,IAAG;AAC5B,cAAe,UAAU,IAAG;EC6NxB,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED9NF,yBAAA;;AAUF;ECiNI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;EAoCF,mEAAA;EDrPA,kBAAA;ECaA,2FAAA;EACQ,mFAAA;;ADjBV,eAOE,YAAY,UAAU;EC0MpB,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;EApMF,wDAAA;EACQ,gDAAA;;ADLV;AACA,WAAY,KAAK;EACf,8CAAA;;AAIF;EC+LI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;EAoCF,mEAAA;;ADtOF,eAIE,YAAY,UAAU;EC2LpB,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;EApMF,uDAAA;EACQ,+CAAA;;ADCV,eASE;AATF,eAUE,YAAY,KAAK;EACf,yCAAA;;AAKJ;AACA;AACA;EACE,gBAAA;;AAUF;EACE,6CAAA;EChCA,0FAAA;EACQ,kFAAA;;AD2CV;ECqJI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED5JF,qBAAA;;AAKF;ECoJI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED5JF,qBAAA;;AAMF;ECmJI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED5JF,qBAAA;;AAOF;ECkJI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED5JF,qBAAA;;AAgBF;ECyII,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADlIJ;EC+HI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADjIJ;EC8HI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADhIJ;EC6HI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;AD/HJ;EC4HI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;AD9HJ;EC2HI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADtHJ;EACE,kBAAA;EC/EA,kDAAA;EACQ,0CAAA;;ADiFV,gBAAgB;AAChB,gBAAgB,OAAO;AACvB,gBAAgB,OAAO;EACrB,6BAAA;EC4GE,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED7GF,qBAAA;;AAUF;ECjGE,iDAAA;EACQ,yCAAA;;AD0GV,cAAe;ECsFX,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADxFJ,cAAe;ECqFX,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADvFJ,cAAe;ECoFX,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADtFJ,WAAY;ECmFR,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADrFJ,cAAe;ECkFX,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADpFJ,aAAc;ECiFV,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;AD5EJ;ECyEI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED1EF,qBAAA;EC1HA,yFAAA;EACQ,iFAAA","sourcesContent":["\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n // Reset the shadow\n &:active,\n &.active {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners\n background-repeat: repeat-x;\n border-color: darken(@btn-color, 14%);\n\n &:hover,\n &:focus {\n background-color: darken(@btn-color, 12%);\n background-position: 0 -15px;\n }\n\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n border-color: darken(@btn-color, 14%);\n }\n}\n\n// Common styles\n.btn {\n // Remove the gradient for the pressed/active state\n &:active,\n &.active {\n background-image: none;\n }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger { .btn-styles(@btn-danger-bg); }\n\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n border-radius: @navbar-border-radius;\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: darken(@navbar-default-bg, 5%); @end-color: darken(@navbar-default-bg, 2%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: @navbar-inverse-bg; @end-color: lighten(@navbar-inverse-bg, 2.5%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n }\n\n .navbar-brand,\n .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n text-shadow: 0 1px 0 rgba(255,255,255,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success { .alert-styles(@alert-success-bg); }\n.alert-info { .alert-styles(@alert-info-bg); }\n.alert-warning { .alert-styles(@alert-warning-bg); }\n.alert-danger { .alert-styles(@alert-danger-bg); }\n\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }\n\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n border-radius: @border-radius-base;\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n border-color: darken(@list-group-active-border, 7.5%);\n}\n\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n border-color: darken(@well-bg, 10%);\n @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n}\n","//\n// Mixins\n// --------------------------------------------------\n\n\n// Utilities\n// -------------------------\n\n// Clearfix\n// Source: http://nicolasgallagher.com/micro-clearfix-hack/\n//\n// For modern browsers\n// 1. The space content is one way to avoid an Opera bug when the\n// contenteditable attribute is included anywhere else in the document.\n// Otherwise it causes space to appear at the top and bottom of elements\n// that are clearfixed.\n// 2. The use of `table` rather than `block` is only necessary if using\n// `:before` to contain the top-margins of child elements.\n.clearfix() {\n &:before,\n &:after {\n content: \" \"; // 1\n display: table; // 2\n }\n &:after {\n clear: both;\n }\n}\n\n// WebKit-style focus\n.tab-focus() {\n // Default\n outline: thin dotted;\n // WebKit\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n\n// Center-align a block level element\n.center-block() {\n display: block;\n margin-left: auto;\n margin-right: auto;\n}\n\n// Sizing shortcuts\n.size(@width; @height) {\n width: @width;\n height: @height;\n}\n.square(@size) {\n .size(@size; @size);\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n &::-moz-placeholder { color: @color; // Firefox\n opacity: 1; } // See https://github.com/twbs/bootstrap/pull/11526\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Text overflow\n// Requires inline-block or block for proper styling\n.text-overflow() {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n// CSS image replacement\n//\n// Heads up! v3 launched with with only `.hide-text()`, but per our pattern for\n// mixins being reused as classes with the same name, this doesn't hold up. As\n// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`. Note\n// that we cannot chain the mixins together in Less, so they are repeated.\n//\n// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757\n\n// Deprecated as of v3.0.1 (will be removed in v4)\n.hide-text() {\n font: ~\"0/0\" a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n// New mixin to use as of v3.0.1\n.text-hide() {\n .hide-text();\n}\n\n\n\n// CSS3 PROPERTIES\n// --------------------------------------------------\n\n// Single side border-radius\n.border-top-radius(@radius) {\n border-top-right-radius: @radius;\n border-top-left-radius: @radius;\n}\n.border-right-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-top-right-radius: @radius;\n}\n.border-bottom-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-bottom-left-radius: @radius;\n}\n.border-left-radius(@radius) {\n border-bottom-left-radius: @radius;\n border-top-left-radius: @radius;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support the\n// standard `box-shadow` property.\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Transitions\n.transition(@transition) {\n -webkit-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n// Transformations\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n transform: rotate(@degrees);\n}\n.scale(@ratio; @ratio-y...) {\n -webkit-transform: scale(@ratio, @ratio-y);\n -ms-transform: scale(@ratio, @ratio-y); // IE9 only\n transform: scale(@ratio, @ratio-y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n transform: translate(@x, @y);\n}\n.skew(@x; @y) {\n -webkit-transform: skew(@x, @y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n transform: skew(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n.backface-visibility(@visibility){\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// User select\n// For selecting text on the page\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n\n// Resize anything\n.resizable(@direction) {\n resize: @direction; // Options: horizontal, vertical, both\n overflow: auto; // Safari fix\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Opacity\n.opacity(@opacity) {\n opacity: @opacity;\n // IE8 filter\n @opacity-ie: (@opacity * 100);\n filter: ~\"alpha(opacity=@{opacity-ie})\";\n}\n\n\n\n// GRADIENTS\n// --------------------------------------------------\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, color-stop(@start-color @start-percent), color-stop(@end-color @end-percent)); // Safari 5.1-6, Chrome 10+\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n\n// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n\n\n\n// Retina images\n//\n// Short retina mixin for setting background-image and -size\n\n.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {\n background-image: url(\"@{file-1x}\");\n\n @media\n only screen and (-webkit-min-device-pixel-ratio: 2),\n only screen and ( min--moz-device-pixel-ratio: 2),\n only screen and ( -o-min-device-pixel-ratio: 2/1),\n only screen and ( min-device-pixel-ratio: 2),\n only screen and ( min-resolution: 192dpi),\n only screen and ( min-resolution: 2dppx) {\n background-image: url(\"@{file-2x}\");\n background-size: @width-1x @height-1x;\n }\n}\n\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n\n.img-responsive(@display: block) {\n display: @display;\n max-width: 100%; // Part 1: Set a maximum relative to the parent\n height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching\n}\n\n\n// COMPONENT MIXINS\n// --------------------------------------------------\n\n// Horizontal dividers\n// -------------------------\n// Dividers (basically an hr) within dropdowns and nav lists\n.nav-divider(@color: #e5e5e5) {\n height: 1px;\n margin: ((@line-height-computed / 2) - 1) 0;\n overflow: hidden;\n background-color: @color;\n}\n\n// Panels\n// -------------------------\n.panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) {\n border-color: @border;\n\n & > .panel-heading {\n color: @heading-text-color;\n background-color: @heading-bg-color;\n border-color: @heading-border;\n\n + .panel-collapse .panel-body {\n border-top-color: @border;\n }\n }\n & > .panel-footer {\n + .panel-collapse .panel-body {\n border-bottom-color: @border;\n }\n }\n}\n\n// Alerts\n// -------------------------\n.alert-variant(@background; @border; @text-color) {\n background-color: @background;\n border-color: @border;\n color: @text-color;\n\n hr {\n border-top-color: darken(@border, 5%);\n }\n .alert-link {\n color: darken(@text-color, 10%);\n }\n}\n\n// Tables\n// -------------------------\n.table-row-variant(@state; @background) {\n // Exact selectors below required to override `.table-striped` and prevent\n // inheritance to nested tables.\n .table > thead > tr,\n .table > tbody > tr,\n .table > tfoot > tr {\n > td.@{state},\n > th.@{state},\n &.@{state} > td,\n &.@{state} > th {\n background-color: @background;\n }\n }\n\n // Hover states for `.table-hover`\n // Note: this is not available for cells or rows within `thead` or `tfoot`.\n .table-hover > tbody > tr {\n > td.@{state}:hover,\n > th.@{state}:hover,\n &.@{state}:hover > td,\n &.@{state}:hover > th {\n background-color: darken(@background, 5%);\n }\n }\n}\n\n// List Groups\n// -------------------------\n.list-group-item-variant(@state; @background; @color) {\n .list-group-item-@{state} {\n color: @color;\n background-color: @background;\n\n a& {\n color: @color;\n\n .list-group-item-heading { color: inherit; }\n\n &:hover,\n &:focus {\n color: @color;\n background-color: darken(@background, 5%);\n }\n &.active,\n &.active:hover,\n &.active:focus {\n color: #fff;\n background-color: @color;\n border-color: @color;\n }\n }\n }\n}\n\n// Button variants\n// -------------------------\n// Easily pump out default styles, as well as :hover, :focus, :active,\n// and disabled options for all buttons\n.button-variant(@color; @background; @border) {\n color: @color;\n background-color: @background;\n border-color: @border;\n\n &:hover,\n &:focus,\n &:active,\n &.active,\n .open .dropdown-toggle& {\n color: @color;\n background-color: darken(@background, 8%);\n border-color: darken(@border, 12%);\n }\n &:active,\n &.active,\n .open .dropdown-toggle& {\n background-image: none;\n }\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &,\n &:hover,\n &:focus,\n &:active,\n &.active {\n background-color: @background;\n border-color: @border;\n }\n }\n\n .badge {\n color: @background;\n background-color: @color;\n }\n}\n\n// Button sizes\n// -------------------------\n.button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n}\n\n// Pagination\n// -------------------------\n.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @border-radius) {\n > li {\n > a,\n > span {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n }\n &:first-child {\n > a,\n > span {\n .border-left-radius(@border-radius);\n }\n }\n &:last-child {\n > a,\n > span {\n .border-right-radius(@border-radius);\n }\n }\n }\n}\n\n// Labels\n// -------------------------\n.label-variant(@color) {\n background-color: @color;\n &[href] {\n &:hover,\n &:focus {\n background-color: darken(@color, 10%);\n }\n }\n}\n\n// Contextual backgrounds\n// -------------------------\n.bg-variant(@color) {\n background-color: @color;\n a&:hover {\n background-color: darken(@color, 10%);\n }\n}\n\n// Typography\n// -------------------------\n.text-emphasis-variant(@color) {\n color: @color;\n a&:hover {\n color: darken(@color, 10%);\n }\n}\n\n// Navbar vertical align\n// -------------------------\n// Vertically center elements in the navbar.\n// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.\n.navbar-vertical-align(@element-height) {\n margin-top: ((@navbar-height - @element-height) / 2);\n margin-bottom: ((@navbar-height - @element-height) / 2);\n}\n\n// Progress bars\n// -------------------------\n.progress-bar-variant(@color) {\n background-color: @color;\n .progress-striped & {\n #gradient > .striped();\n }\n}\n\n// Responsive utilities\n// -------------------------\n// More easily include all the states for responsive-utilities.less.\n.responsive-visibility() {\n display: block !important;\n table& { display: table; }\n tr& { display: table-row !important; }\n th&,\n td& { display: table-cell !important; }\n}\n\n.responsive-invisibility() {\n display: none !important;\n}\n\n\n// Grid System\n// -----------\n\n// Centered container element\n.container-fixed() {\n margin-right: auto;\n margin-left: auto;\n padding-left: (@grid-gutter-width / 2);\n padding-right: (@grid-gutter-width / 2);\n &:extend(.clearfix all);\n}\n\n// Creates a wrapper for a series of columns\n.make-row(@gutter: @grid-gutter-width) {\n margin-left: (@gutter / -2);\n margin-right: (@gutter / -2);\n &:extend(.clearfix all);\n}\n\n// Generate the extra small columns\n.make-xs-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n float: left;\n width: percentage((@columns / @grid-columns));\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n}\n.make-xs-column-offset(@columns) {\n @media (min-width: @screen-xs-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-xs-column-push(@columns) {\n @media (min-width: @screen-xs-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-xs-column-pull(@columns) {\n @media (min-width: @screen-xs-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Generate the small columns\n.make-sm-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-sm-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-offset(@columns) {\n @media (min-width: @screen-sm-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-push(@columns) {\n @media (min-width: @screen-sm-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-pull(@columns) {\n @media (min-width: @screen-sm-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Generate the medium columns\n.make-md-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-md-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-offset(@columns) {\n @media (min-width: @screen-md-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-push(@columns) {\n @media (min-width: @screen-md-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-pull(@columns) {\n @media (min-width: @screen-md-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Generate the large columns\n.make-lg-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-lg-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-offset(@columns) {\n @media (min-width: @screen-lg-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-push(@columns) {\n @media (min-width: @screen-lg-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-pull(@columns) {\n @media (min-width: @screen-lg-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `@grid-columns`.\n\n.make-grid-columns() {\n // Common styles for all sizes of grid columns, widths 1-12\n .col(@index) when (@index = 1) { // initial\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general; \"=<\" isn't a typo\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n position: relative;\n // Prevent columns from collapsing when empty\n min-height: 1px;\n // Inner gutter via padding\n padding-left: (@grid-gutter-width / 2);\n padding-right: (@grid-gutter-width / 2);\n }\n }\n .col(1); // kickstart it\n}\n\n.float-grid-columns(@class) {\n .col(@index) when (@index = 1) { // initial\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n float: left;\n }\n }\n .col(1); // kickstart it\n}\n\n.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {\n .col-@{class}-@{index} {\n width: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) {\n .col-@{class}-push-@{index} {\n left: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) {\n .col-@{class}-pull-@{index} {\n right: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = offset) {\n .col-@{class}-offset-@{index} {\n margin-left: percentage((@index / @grid-columns));\n }\n}\n\n// Basic looping in LESS\n.loop-grid-columns(@index, @class, @type) when (@index >= 0) {\n .calc-grid-column(@index, @class, @type);\n // next iteration\n .loop-grid-columns((@index - 1), @class, @type);\n}\n\n// Create grid for specific class\n.make-grid(@class) {\n .float-grid-columns(@class);\n .loop-grid-columns(@grid-columns, @class, width);\n .loop-grid-columns(@grid-columns, @class, pull);\n .loop-grid-columns(@grid-columns, @class, push);\n .loop-grid-columns(@grid-columns, @class, offset);\n}\n\n// Form validation states\n//\n// Used in forms.less to generate the form validation CSS for warnings, errors,\n// and successes.\n\n.form-control-validation(@text-color: #555; @border-color: #ccc; @background-color: #f5f5f5) {\n // Color the label and help text\n .help-block,\n .control-label,\n .radio,\n .checkbox,\n .radio-inline,\n .checkbox-inline {\n color: @text-color;\n }\n // Set the border and box shadow on specific inputs to match\n .form-control {\n border-color: @border-color;\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work\n &:focus {\n border-color: darken(@border-color, 10%);\n @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@border-color, 20%);\n .box-shadow(@shadow);\n }\n }\n // Set validation states also for addons\n .input-group-addon {\n color: @text-color;\n border-color: @border-color;\n background-color: @background-color;\n }\n // Optional feedback icon\n .form-control-feedback {\n color: @text-color;\n }\n}\n\n// Form control focus state\n//\n// Generate a customized focus state and for any input with the specified color,\n// which defaults to the `@input-focus-border` variable.\n//\n// We highly encourage you to not customize the default value, but instead use\n// this to tweak colors on an as-needed basis. This aesthetic change is based on\n// WebKit's default styles, but applicable to a wider range of browsers. Its\n// usability and accessibility should be taken into account with any change.\n//\n// Example usage: change the default blue border and shadow to white for better\n// contrast against a dark gray background.\n\n.form-control-focus(@color: @input-border-focus) {\n @color-rgba: rgba(red(@color), green(@color), blue(@color), .6);\n &:focus {\n border-color: @color;\n outline: 0;\n .box-shadow(~\"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px @{color-rgba}\");\n }\n}\n\n// Form control sizing\n//\n// Relative text size, padding, and border-radii changes for form controls. For\n// horizontal sizing, wrap controls in the predefined grid classes. ``\n// element gets special love because it's special, and that's a fact!\n\n.input-size(@input-height; @padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n height: @input-height;\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n\n select& {\n height: @input-height;\n line-height: @input-height;\n }\n\n textarea&,\n select[multiple]& {\n height: auto;\n }\n}\n","//\n// Variables\n// --------------------------------------------------\n\n\n//== Colors\n//\n//## Gray and brand colors for use across Bootstrap.\n\n@gray-darker: lighten(#000, 13.5%); // #222\n@gray-dark: lighten(#000, 20%); // #333\n@gray: lighten(#000, 33.5%); // #555\n@gray-light: lighten(#000, 60%); // #999\n@gray-lighter: lighten(#000, 93.5%); // #eee\n\n@brand-primary: #428bca;\n@brand-success: #5cb85c;\n@brand-info: #5bc0de;\n@brand-warning: #f0ad4e;\n@brand-danger: #d9534f;\n\n\n//== Scaffolding\n//\n// ## Settings for some of the most global styles.\n\n//** Background color for ``.\n@body-bg: #fff;\n//** Global text color on ``.\n@text-color: @gray-dark;\n\n//** Global textual link color.\n@link-color: @brand-primary;\n//** Link hover color set via `darken()` function.\n@link-hover-color: darken(@link-color, 15%);\n\n\n//== Typography\n//\n//## Font, line-height, and color for body text, headings, and more.\n\n@font-family-sans-serif: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n@font-family-serif: Georgia, \"Times New Roman\", Times, serif;\n//** Default monospace fonts for ``, ``, and `
    `.\n@font-family-monospace:   Menlo, Monaco, Consolas, \"Courier New\", monospace;\n@font-family-base:        @font-family-sans-serif;\n\n@font-size-base:          14px;\n@font-size-large:         ceil((@font-size-base * 1.25)); // ~18px\n@font-size-small:         ceil((@font-size-base * 0.85)); // ~12px\n\n@font-size-h1:            floor((@font-size-base * 2.6)); // ~36px\n@font-size-h2:            floor((@font-size-base * 2.15)); // ~30px\n@font-size-h3:            ceil((@font-size-base * 1.7)); // ~24px\n@font-size-h4:            ceil((@font-size-base * 1.25)); // ~18px\n@font-size-h5:            @font-size-base;\n@font-size-h6:            ceil((@font-size-base * 0.85)); // ~12px\n\n//** Unit-less `line-height` for use in components like buttons.\n@line-height-base:        1.428571429; // 20/14\n//** Computed \"line-height\" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.\n@line-height-computed:    floor((@font-size-base * @line-height-base)); // ~20px\n\n//** By default, this inherits from the ``.\n@headings-font-family:    inherit;\n@headings-font-weight:    500;\n@headings-line-height:    1.1;\n@headings-color:          inherit;\n\n\n//-- Iconography\n//\n//## Specify custom locations of the include Glyphicons icon font. Useful for those including Bootstrap via Bower.\n\n@icon-font-path:          \"../fonts/\";\n@icon-font-name:          \"glyphicons-halflings-regular\";\n@icon-font-svg-id:        \"glyphicons_halflingsregular\";\n\n//== Components\n//\n//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).\n\n@padding-base-vertical:     6px;\n@padding-base-horizontal:   12px;\n\n@padding-large-vertical:    10px;\n@padding-large-horizontal:  16px;\n\n@padding-small-vertical:    5px;\n@padding-small-horizontal:  10px;\n\n@padding-xs-vertical:       1px;\n@padding-xs-horizontal:     5px;\n\n@line-height-large:         1.33;\n@line-height-small:         1.5;\n\n@border-radius-base:        4px;\n@border-radius-large:       6px;\n@border-radius-small:       3px;\n\n//** Global color for active items (e.g., navs or dropdowns).\n@component-active-color:    #fff;\n//** Global background color for active items (e.g., navs or dropdowns).\n@component-active-bg:       @brand-primary;\n\n//** Width of the `border` for generating carets that indicator dropdowns.\n@caret-width-base:          4px;\n//** Carets increase slightly in size for larger components.\n@caret-width-large:         5px;\n\n\n//== Tables\n//\n//## Customizes the `.table` component with basic values, each used across all table variations.\n\n//** Padding for ``s and ``s.\n@table-cell-padding:            8px;\n//** Padding for cells in `.table-condensed`.\n@table-condensed-cell-padding:  5px;\n\n//** Default background color used for all tables.\n@table-bg:                      transparent;\n//** Background color used for `.table-striped`.\n@table-bg-accent:               #f9f9f9;\n//** Background color used for `.table-hover`.\n@table-bg-hover:                #f5f5f5;\n@table-bg-active:               @table-bg-hover;\n\n//** Border color for table and cell borders.\n@table-border-color:            #ddd;\n\n\n//== Buttons\n//\n//## For each of Bootstrap's buttons, define text, background and border color.\n\n@btn-font-weight:                normal;\n\n@btn-default-color:              #333;\n@btn-default-bg:                 #fff;\n@btn-default-border:             #ccc;\n\n@btn-primary-color:              #fff;\n@btn-primary-bg:                 @brand-primary;\n@btn-primary-border:             darken(@btn-primary-bg, 5%);\n\n@btn-success-color:              #fff;\n@btn-success-bg:                 @brand-success;\n@btn-success-border:             darken(@btn-success-bg, 5%);\n\n@btn-info-color:                 #fff;\n@btn-info-bg:                    @brand-info;\n@btn-info-border:                darken(@btn-info-bg, 5%);\n\n@btn-warning-color:              #fff;\n@btn-warning-bg:                 @brand-warning;\n@btn-warning-border:             darken(@btn-warning-bg, 5%);\n\n@btn-danger-color:               #fff;\n@btn-danger-bg:                  @brand-danger;\n@btn-danger-border:              darken(@btn-danger-bg, 5%);\n\n@btn-link-disabled-color:        @gray-light;\n\n\n//== Forms\n//\n//##\n\n//** `` background color\n@input-bg:                       #fff;\n//** `` background color\n@input-bg-disabled:              @gray-lighter;\n\n//** Text color for ``s\n@input-color:                    @gray;\n//** `` border color\n@input-border:                   #ccc;\n//** `` border radius\n@input-border-radius:            @border-radius-base;\n//** Border color for inputs on focus\n@input-border-focus:             #66afe9;\n\n//** Placeholder text color\n@input-color-placeholder:        @gray-light;\n\n//** Default `.form-control` height\n@input-height-base:              (@line-height-computed + (@padding-base-vertical * 2) + 2);\n//** Large `.form-control` height\n@input-height-large:             (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);\n//** Small `.form-control` height\n@input-height-small:             (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2);\n\n@legend-color:                   @gray-dark;\n@legend-border-color:            #e5e5e5;\n\n//** Background color for textual input addons\n@input-group-addon-bg:           @gray-lighter;\n//** Border color for textual input addons\n@input-group-addon-border-color: @input-border;\n\n\n//== Dropdowns\n//\n//## Dropdown menu container and contents.\n\n//** Background for the dropdown menu.\n@dropdown-bg:                    #fff;\n//** Dropdown menu `border-color`.\n@dropdown-border:                rgba(0,0,0,.15);\n//** Dropdown menu `border-color` **for IE8**.\n@dropdown-fallback-border:       #ccc;\n//** Divider color for between dropdown items.\n@dropdown-divider-bg:            #e5e5e5;\n\n//** Dropdown link text color.\n@dropdown-link-color:            @gray-dark;\n//** Hover color for dropdown links.\n@dropdown-link-hover-color:      darken(@gray-dark, 5%);\n//** Hover background for dropdown links.\n@dropdown-link-hover-bg:         #f5f5f5;\n\n//** Active dropdown menu item text color.\n@dropdown-link-active-color:     @component-active-color;\n//** Active dropdown menu item background color.\n@dropdown-link-active-bg:        @component-active-bg;\n\n//** Disabled dropdown menu item background color.\n@dropdown-link-disabled-color:   @gray-light;\n\n//** Text color for headers within dropdown menus.\n@dropdown-header-color:          @gray-light;\n\n// Note: Deprecated @dropdown-caret-color as of v3.1.0\n@dropdown-caret-color:           #000;\n\n\n//-- Z-index master list\n//\n// Warning: Avoid customizing these values. They're used for a bird's eye view\n// of components dependent on the z-axis and are designed to all work together.\n//\n// Note: These variables are not generated into the Customizer.\n\n@zindex-navbar:            1000;\n@zindex-dropdown:          1000;\n@zindex-popover:           1010;\n@zindex-tooltip:           1030;\n@zindex-navbar-fixed:      1030;\n@zindex-modal-background:  1040;\n@zindex-modal:             1050;\n\n\n//== Media queries breakpoints\n//\n//## Define the breakpoints at which your layout will change, adapting to different screen sizes.\n\n// Extra small screen / phone\n// Note: Deprecated @screen-xs and @screen-phone as of v3.0.1\n@screen-xs:                  480px;\n@screen-xs-min:              @screen-xs;\n@screen-phone:               @screen-xs-min;\n\n// Small screen / tablet\n// Note: Deprecated @screen-sm and @screen-tablet as of v3.0.1\n@screen-sm:                  768px;\n@screen-sm-min:              @screen-sm;\n@screen-tablet:              @screen-sm-min;\n\n// Medium screen / desktop\n// Note: Deprecated @screen-md and @screen-desktop as of v3.0.1\n@screen-md:                  992px;\n@screen-md-min:              @screen-md;\n@screen-desktop:             @screen-md-min;\n\n// Large screen / wide desktop\n// Note: Deprecated @screen-lg and @screen-lg-desktop as of v3.0.1\n@screen-lg:                  1200px;\n@screen-lg-min:              @screen-lg;\n@screen-lg-desktop:          @screen-lg-min;\n\n// So media queries don't overlap when required, provide a maximum\n@screen-xs-max:              (@screen-sm-min - 1);\n@screen-sm-max:              (@screen-md-min - 1);\n@screen-md-max:              (@screen-lg-min - 1);\n\n\n//== Grid system\n//\n//## Define your custom responsive grid.\n\n//** Number of columns in the grid.\n@grid-columns:              12;\n//** Padding between columns. Gets divided in half for the left and right.\n@grid-gutter-width:         30px;\n// Navbar collapse\n//** Point at which the navbar becomes uncollapsed.\n@grid-float-breakpoint:     @screen-sm-min;\n//** Point at which the navbar begins collapsing.\n@grid-float-breakpoint-max: (@grid-float-breakpoint - 1);\n\n\n//== Container sizes\n//\n//## Define the maximum width of `.container` for different screen sizes.\n\n// Small screen / tablet\n@container-tablet:             ((720px + @grid-gutter-width));\n//** For `@screen-sm-min` and up.\n@container-sm:                 @container-tablet;\n\n// Medium screen / desktop\n@container-desktop:            ((940px + @grid-gutter-width));\n//** For `@screen-md-min` and up.\n@container-md:                 @container-desktop;\n\n// Large screen / wide desktop\n@container-large-desktop:      ((1140px + @grid-gutter-width));\n//** For `@screen-lg-min` and up.\n@container-lg:                 @container-large-desktop;\n\n\n//== Navbar\n//\n//##\n\n// Basics of a navbar\n@navbar-height:                    50px;\n@navbar-margin-bottom:             @line-height-computed;\n@navbar-border-radius:             @border-radius-base;\n@navbar-padding-horizontal:        floor((@grid-gutter-width / 2));\n@navbar-padding-vertical:          ((@navbar-height - @line-height-computed) / 2);\n@navbar-collapse-max-height:       340px;\n\n@navbar-default-color:             #777;\n@navbar-default-bg:                #f8f8f8;\n@navbar-default-border:            darken(@navbar-default-bg, 6.5%);\n\n// Navbar links\n@navbar-default-link-color:                #777;\n@navbar-default-link-hover-color:          #333;\n@navbar-default-link-hover-bg:             transparent;\n@navbar-default-link-active-color:         #555;\n@navbar-default-link-active-bg:            darken(@navbar-default-bg, 6.5%);\n@navbar-default-link-disabled-color:       #ccc;\n@navbar-default-link-disabled-bg:          transparent;\n\n// Navbar brand label\n@navbar-default-brand-color:               @navbar-default-link-color;\n@navbar-default-brand-hover-color:         darken(@navbar-default-brand-color, 10%);\n@navbar-default-brand-hover-bg:            transparent;\n\n// Navbar toggle\n@navbar-default-toggle-hover-bg:           #ddd;\n@navbar-default-toggle-icon-bar-bg:        #888;\n@navbar-default-toggle-border-color:       #ddd;\n\n\n// Inverted navbar\n// Reset inverted navbar basics\n@navbar-inverse-color:                      @gray-light;\n@navbar-inverse-bg:                         #222;\n@navbar-inverse-border:                     darken(@navbar-inverse-bg, 10%);\n\n// Inverted navbar links\n@navbar-inverse-link-color:                 @gray-light;\n@navbar-inverse-link-hover-color:           #fff;\n@navbar-inverse-link-hover-bg:              transparent;\n@navbar-inverse-link-active-color:          @navbar-inverse-link-hover-color;\n@navbar-inverse-link-active-bg:             darken(@navbar-inverse-bg, 10%);\n@navbar-inverse-link-disabled-color:        #444;\n@navbar-inverse-link-disabled-bg:           transparent;\n\n// Inverted navbar brand label\n@navbar-inverse-brand-color:                @navbar-inverse-link-color;\n@navbar-inverse-brand-hover-color:          #fff;\n@navbar-inverse-brand-hover-bg:             transparent;\n\n// Inverted navbar toggle\n@navbar-inverse-toggle-hover-bg:            #333;\n@navbar-inverse-toggle-icon-bar-bg:         #fff;\n@navbar-inverse-toggle-border-color:        #333;\n\n\n//== Navs\n//\n//##\n\n//=== Shared nav styles\n@nav-link-padding:                          10px 15px;\n@nav-link-hover-bg:                         @gray-lighter;\n\n@nav-disabled-link-color:                   @gray-light;\n@nav-disabled-link-hover-color:             @gray-light;\n\n@nav-open-link-hover-color:                 #fff;\n\n//== Tabs\n@nav-tabs-border-color:                     #ddd;\n\n@nav-tabs-link-hover-border-color:          @gray-lighter;\n\n@nav-tabs-active-link-hover-bg:             @body-bg;\n@nav-tabs-active-link-hover-color:          @gray;\n@nav-tabs-active-link-hover-border-color:   #ddd;\n\n@nav-tabs-justified-link-border-color:            #ddd;\n@nav-tabs-justified-active-link-border-color:     @body-bg;\n\n//== Pills\n@nav-pills-border-radius:                   @border-radius-base;\n@nav-pills-active-link-hover-bg:            @component-active-bg;\n@nav-pills-active-link-hover-color:         @component-active-color;\n\n\n//== Pagination\n//\n//##\n\n@pagination-color:                     @link-color;\n@pagination-bg:                        #fff;\n@pagination-border:                    #ddd;\n\n@pagination-hover-color:               @link-hover-color;\n@pagination-hover-bg:                  @gray-lighter;\n@pagination-hover-border:              #ddd;\n\n@pagination-active-color:              #fff;\n@pagination-active-bg:                 @brand-primary;\n@pagination-active-border:             @brand-primary;\n\n@pagination-disabled-color:            @gray-light;\n@pagination-disabled-bg:               #fff;\n@pagination-disabled-border:           #ddd;\n\n\n//== Pager\n//\n//##\n\n@pager-bg:                             @pagination-bg;\n@pager-border:                         @pagination-border;\n@pager-border-radius:                  15px;\n\n@pager-hover-bg:                       @pagination-hover-bg;\n\n@pager-active-bg:                      @pagination-active-bg;\n@pager-active-color:                   @pagination-active-color;\n\n@pager-disabled-color:                 @pagination-disabled-color;\n\n\n//== Jumbotron\n//\n//##\n\n@jumbotron-padding:              30px;\n@jumbotron-color:                inherit;\n@jumbotron-bg:                   @gray-lighter;\n@jumbotron-heading-color:        inherit;\n@jumbotron-font-size:            ceil((@font-size-base * 1.5));\n\n\n//== Form states and alerts\n//\n//## Define colors for form feedback states and, by default, alerts.\n\n@state-success-text:             #3c763d;\n@state-success-bg:               #dff0d8;\n@state-success-border:           darken(spin(@state-success-bg, -10), 5%);\n\n@state-info-text:                #31708f;\n@state-info-bg:                  #d9edf7;\n@state-info-border:              darken(spin(@state-info-bg, -10), 7%);\n\n@state-warning-text:             #8a6d3b;\n@state-warning-bg:               #fcf8e3;\n@state-warning-border:           darken(spin(@state-warning-bg, -10), 5%);\n\n@state-danger-text:              #a94442;\n@state-danger-bg:                #f2dede;\n@state-danger-border:            darken(spin(@state-danger-bg, -10), 5%);\n\n\n//== Tooltips\n//\n//##\n\n//** Tooltip max width\n@tooltip-max-width:           200px;\n//** Tooltip text color\n@tooltip-color:               #fff;\n//** Tooltip background color\n@tooltip-bg:                  #000;\n@tooltip-opacity:             .9;\n\n//** Tooltip arrow width\n@tooltip-arrow-width:         5px;\n//** Tooltip arrow color\n@tooltip-arrow-color:         @tooltip-bg;\n\n\n//== Popovers\n//\n//##\n\n//** Popover body background color\n@popover-bg:                          #fff;\n//** Popover maximum width\n@popover-max-width:                   276px;\n//** Popover border color\n@popover-border-color:                rgba(0,0,0,.2);\n//** Popover fallback border color\n@popover-fallback-border-color:       #ccc;\n\n//** Popover title background color\n@popover-title-bg:                    darken(@popover-bg, 3%);\n\n//** Popover arrow width\n@popover-arrow-width:                 10px;\n//** Popover arrow color\n@popover-arrow-color:                 #fff;\n\n//** Popover outer arrow width\n@popover-arrow-outer-width:           (@popover-arrow-width + 1);\n//** Popover outer arrow color\n@popover-arrow-outer-color:           fadein(@popover-border-color, 5%);\n//** Popover outer arrow fallback color\n@popover-arrow-outer-fallback-color:  darken(@popover-fallback-border-color, 20%);\n\n\n//== Labels\n//\n//##\n\n//** Default label background color\n@label-default-bg:            @gray-light;\n//** Primary label background color\n@label-primary-bg:            @brand-primary;\n//** Success label background color\n@label-success-bg:            @brand-success;\n//** Info label background color\n@label-info-bg:               @brand-info;\n//** Warning label background color\n@label-warning-bg:            @brand-warning;\n//** Danger label background color\n@label-danger-bg:             @brand-danger;\n\n//** Default label text color\n@label-color:                 #fff;\n//** Default text color of a linked label\n@label-link-hover-color:      #fff;\n\n\n//== Modals\n//\n//##\n\n//** Padding applied to the modal body\n@modal-inner-padding:         20px;\n\n//** Padding applied to the modal title\n@modal-title-padding:         15px;\n//** Modal title line-height\n@modal-title-line-height:     @line-height-base;\n\n//** Background color of modal content area\n@modal-content-bg:                             #fff;\n//** Modal content border color\n@modal-content-border-color:                   rgba(0,0,0,.2);\n//** Modal content border color **for IE8**\n@modal-content-fallback-border-color:          #999;\n\n//** Modal backdrop background color\n@modal-backdrop-bg:           #000;\n//** Modal backdrop opacity\n@modal-backdrop-opacity:      .5;\n//** Modal header border color\n@modal-header-border-color:   #e5e5e5;\n//** Modal footer border color\n@modal-footer-border-color:   @modal-header-border-color;\n\n@modal-lg:                    900px;\n@modal-md:                    600px;\n@modal-sm:                    300px;\n\n\n//== Alerts\n//\n//## Define alert colors, border radius, and padding.\n\n@alert-padding:               15px;\n@alert-border-radius:         @border-radius-base;\n@alert-link-font-weight:      bold;\n\n@alert-success-bg:            @state-success-bg;\n@alert-success-text:          @state-success-text;\n@alert-success-border:        @state-success-border;\n\n@alert-info-bg:               @state-info-bg;\n@alert-info-text:             @state-info-text;\n@alert-info-border:           @state-info-border;\n\n@alert-warning-bg:            @state-warning-bg;\n@alert-warning-text:          @state-warning-text;\n@alert-warning-border:        @state-warning-border;\n\n@alert-danger-bg:             @state-danger-bg;\n@alert-danger-text:           @state-danger-text;\n@alert-danger-border:         @state-danger-border;\n\n\n//== Progress bars\n//\n//##\n\n//** Background color of the whole progress component\n@progress-bg:                 #f5f5f5;\n//** Progress bar text color\n@progress-bar-color:          #fff;\n\n//** Default progress bar color\n@progress-bar-bg:             @brand-primary;\n//** Success progress bar color\n@progress-bar-success-bg:     @brand-success;\n//** Warning progress bar color\n@progress-bar-warning-bg:     @brand-warning;\n//** Danger progress bar color\n@progress-bar-danger-bg:      @brand-danger;\n//** Info progress bar color\n@progress-bar-info-bg:        @brand-info;\n\n\n//== List group\n//\n//##\n\n//** Background color on `.list-group-item`\n@list-group-bg:                 #fff;\n//** `.list-group-item` border color\n@list-group-border:             #ddd;\n//** List group border radius\n@list-group-border-radius:      @border-radius-base;\n\n//** Background color of single list elements on hover\n@list-group-hover-bg:           #f5f5f5;\n//** Text color of active list elements\n@list-group-active-color:       @component-active-color;\n//** Background color of active list elements\n@list-group-active-bg:          @component-active-bg;\n//** Border color of active list elements\n@list-group-active-border:      @list-group-active-bg;\n@list-group-active-text-color:  lighten(@list-group-active-bg, 40%);\n\n@list-group-link-color:         #555;\n@list-group-link-heading-color: #333;\n\n\n//== Panels\n//\n//##\n\n@panel-bg:                    #fff;\n@panel-body-padding:          15px;\n@panel-border-radius:         @border-radius-base;\n\n//** Border color for elements within panels\n@panel-inner-border:          #ddd;\n@panel-footer-bg:             #f5f5f5;\n\n@panel-default-text:          @gray-dark;\n@panel-default-border:        #ddd;\n@panel-default-heading-bg:    #f5f5f5;\n\n@panel-primary-text:          #fff;\n@panel-primary-border:        @brand-primary;\n@panel-primary-heading-bg:    @brand-primary;\n\n@panel-success-text:          @state-success-text;\n@panel-success-border:        @state-success-border;\n@panel-success-heading-bg:    @state-success-bg;\n\n@panel-info-text:             @state-info-text;\n@panel-info-border:           @state-info-border;\n@panel-info-heading-bg:       @state-info-bg;\n\n@panel-warning-text:          @state-warning-text;\n@panel-warning-border:        @state-warning-border;\n@panel-warning-heading-bg:    @state-warning-bg;\n\n@panel-danger-text:           @state-danger-text;\n@panel-danger-border:         @state-danger-border;\n@panel-danger-heading-bg:     @state-danger-bg;\n\n\n//== Thumbnails\n//\n//##\n\n//** Padding around the thumbnail image\n@thumbnail-padding:           4px;\n//** Thumbnail background color\n@thumbnail-bg:                @body-bg;\n//** Thumbnail border color\n@thumbnail-border:            #ddd;\n//** Thumbnail border radius\n@thumbnail-border-radius:     @border-radius-base;\n\n//** Custom text color for thumbnail captions\n@thumbnail-caption-color:     @text-color;\n//** Padding around the thumbnail caption\n@thumbnail-caption-padding:   9px;\n\n\n//== Wells\n//\n//##\n\n@well-bg:                     #f5f5f5;\n@well-border:                 darken(@well-bg, 7%);\n\n\n//== Badges\n//\n//##\n\n@badge-color:                 #fff;\n//** Linked badge text color on hover\n@badge-link-hover-color:      #fff;\n@badge-bg:                    @gray-light;\n\n//** Badge text color in active nav link\n@badge-active-color:          @link-color;\n//** Badge background color in active nav link\n@badge-active-bg:             #fff;\n\n@badge-font-weight:           bold;\n@badge-line-height:           1;\n@badge-border-radius:         10px;\n\n\n//== Breadcrumbs\n//\n//##\n\n@breadcrumb-padding-vertical:   8px;\n@breadcrumb-padding-horizontal: 15px;\n//** Breadcrumb background color\n@breadcrumb-bg:                 #f5f5f5;\n//** Breadcrumb text color\n@breadcrumb-color:              #ccc;\n//** Text color of current page in the breadcrumb\n@breadcrumb-active-color:       @gray-light;\n//** Textual separator for between breadcrumb elements\n@breadcrumb-separator:          \"/\";\n\n\n//== Carousel\n//\n//##\n\n@carousel-text-shadow:                        0 1px 2px rgba(0,0,0,.6);\n\n@carousel-control-color:                      #fff;\n@carousel-control-width:                      15%;\n@carousel-control-opacity:                    .5;\n@carousel-control-font-size:                  20px;\n\n@carousel-indicator-active-bg:                #fff;\n@carousel-indicator-border-color:             #fff;\n\n@carousel-caption-color:                      #fff;\n\n\n//== Close\n//\n//##\n\n@close-font-weight:           bold;\n@close-color:                 #000;\n@close-text-shadow:           0 1px 0 #fff;\n\n\n//== Code\n//\n//##\n\n@code-color:                  #c7254e;\n@code-bg:                     #f9f2f4;\n\n@kbd-color:                   #fff;\n@kbd-bg:                      #333;\n\n@pre-bg:                      #f5f5f5;\n@pre-color:                   @gray-dark;\n@pre-border-color:            #ccc;\n@pre-scrollable-max-height:   340px;\n\n\n//== Type\n//\n//##\n\n//** Text muted color\n@text-muted:                  @gray-light;\n//** Abbreviations and acronyms border color\n@abbr-border-color:           @gray-light;\n//** Headings small color\n@headings-small-color:        @gray-light;\n//** Blockquote small color\n@blockquote-small-color:      @gray-light;\n//** Blockquote font size\n@blockquote-font-size:        (@font-size-base * 1.25);\n//** Blockquote border color\n@blockquote-border-color:     @gray-lighter;\n//** Page header border color\n@page-header-border-color:    @gray-lighter;\n\n\n//== Miscellaneous\n//\n//##\n\n//** Horizontal line color.\n@hr-border:                   @gray-lighter;\n\n//** Horizontal offset for forms and lists.\n@component-offset-horizontal: 180px;\n","//\n// Thumbnails\n// --------------------------------------------------\n\n\n// Mixin and adjust the regular image class\n.thumbnail {\n  display: block;\n  padding: @thumbnail-padding;\n  margin-bottom: @line-height-computed;\n  line-height: @line-height-base;\n  background-color: @thumbnail-bg;\n  border: 1px solid @thumbnail-border;\n  border-radius: @thumbnail-border-radius;\n  .transition(all .2s ease-in-out);\n\n  > img,\n  a > img {\n    &:extend(.img-responsive);\n    margin-left: auto;\n    margin-right: auto;\n  }\n\n  // Add a hover state for linked versions only\n  a&:hover,\n  a&:focus,\n  a&.active {\n    border-color: @link-color;\n  }\n\n  // Image captions\n  .caption {\n    padding: @thumbnail-caption-padding;\n    color: @thumbnail-caption-color;\n  }\n}\n","//\n// Carousel\n// --------------------------------------------------\n\n\n// Wrapper for the slide container and indicators\n.carousel {\n  position: relative;\n}\n\n.carousel-inner {\n  position: relative;\n  overflow: hidden;\n  width: 100%;\n\n  > .item {\n    display: none;\n    position: relative;\n    .transition(.6s ease-in-out left);\n\n    // Account for jankitude on images\n    > img,\n    > a > img {\n      &:extend(.img-responsive);\n      line-height: 1;\n    }\n  }\n\n  > .active,\n  > .next,\n  > .prev { display: block; }\n\n  > .active {\n    left: 0;\n  }\n\n  > .next,\n  > .prev {\n    position: absolute;\n    top: 0;\n    width: 100%;\n  }\n\n  > .next {\n    left: 100%;\n  }\n  > .prev {\n    left: -100%;\n  }\n  > .next.left,\n  > .prev.right {\n    left: 0;\n  }\n\n  > .active.left {\n    left: -100%;\n  }\n  > .active.right {\n    left: 100%;\n  }\n\n}\n\n// Left/right controls for nav\n// ---------------------------\n\n.carousel-control {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  width: @carousel-control-width;\n  .opacity(@carousel-control-opacity);\n  font-size: @carousel-control-font-size;\n  color: @carousel-control-color;\n  text-align: center;\n  text-shadow: @carousel-text-shadow;\n  // We can't have this transition here because WebKit cancels the carousel\n  // animation if you trip this while in the middle of another animation.\n\n  // Set gradients for backgrounds\n  &.left {\n    #gradient > .horizontal(@start-color: rgba(0,0,0,.5); @end-color: rgba(0,0,0,.0001));\n  }\n  &.right {\n    left: auto;\n    right: 0;\n    #gradient > .horizontal(@start-color: rgba(0,0,0,.0001); @end-color: rgba(0,0,0,.5));\n  }\n\n  // Hover/focus state\n  &:hover,\n  &:focus {\n    outline: none;\n    color: @carousel-control-color;\n    text-decoration: none;\n    .opacity(.9);\n  }\n\n  // Toggles\n  .icon-prev,\n  .icon-next,\n  .glyphicon-chevron-left,\n  .glyphicon-chevron-right {\n    position: absolute;\n    top: 50%;\n    z-index: 5;\n    display: inline-block;\n  }\n  .icon-prev,\n  .glyphicon-chevron-left {\n    left: 50%;\n  }\n  .icon-next,\n  .glyphicon-chevron-right {\n    right: 50%;\n  }\n  .icon-prev,\n  .icon-next {\n    width:  20px;\n    height: 20px;\n    margin-top: -10px;\n    margin-left: -10px;\n    font-family: serif;\n  }\n\n  .icon-prev {\n    &:before {\n      content: '\\2039';// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039)\n    }\n  }\n  .icon-next {\n    &:before {\n      content: '\\203a';// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A)\n    }\n  }\n}\n\n// Optional indicator pips\n//\n// Add an unordered list with the following class and add a list item for each\n// slide your carousel holds.\n\n.carousel-indicators {\n  position: absolute;\n  bottom: 10px;\n  left: 50%;\n  z-index: 15;\n  width: 60%;\n  margin-left: -30%;\n  padding-left: 0;\n  list-style: none;\n  text-align: center;\n\n  li {\n    display: inline-block;\n    width:  10px;\n    height: 10px;\n    margin: 1px;\n    text-indent: -999px;\n    border: 1px solid @carousel-indicator-border-color;\n    border-radius: 10px;\n    cursor: pointer;\n\n    // IE8-9 hack for event handling\n    //\n    // Internet Explorer 8-9 does not support clicks on elements without a set\n    // `background-color`. We cannot use `filter` since that's not viewed as a\n    // background color by the browser. Thus, a hack is needed.\n    //\n    // For IE8, we set solid black as it doesn't support `rgba()`. For IE9, we\n    // set alpha transparency for the best results possible.\n    background-color: #000 \\9; // IE8\n    background-color: rgba(0,0,0,0); // IE9\n  }\n  .active {\n    margin: 0;\n    width:  12px;\n    height: 12px;\n    background-color: @carousel-indicator-active-bg;\n  }\n}\n\n// Optional captions\n// -----------------------------\n// Hidden by default for smaller viewports\n.carousel-caption {\n  position: absolute;\n  left: 15%;\n  right: 15%;\n  bottom: 20px;\n  z-index: 10;\n  padding-top: 20px;\n  padding-bottom: 20px;\n  color: @carousel-caption-color;\n  text-align: center;\n  text-shadow: @carousel-text-shadow;\n  & .btn {\n    text-shadow: none; // No shadow for button elements in carousel-caption\n  }\n}\n\n\n// Scale up controls for tablets and up\n@media screen and (min-width: @screen-sm-min) {\n\n  // Scale up the controls a smidge\n  .carousel-control {\n    .glyphicon-chevron-left,\n    .glyphicon-chevron-right,\n    .icon-prev,\n    .icon-next {\n      width: 30px;\n      height: 30px;\n      margin-top: -15px;\n      margin-left: -15px;\n      font-size: 30px;\n    }\n  }\n\n  // Show and left align the captions\n  .carousel-caption {\n    left: 20%;\n    right: 20%;\n    padding-bottom: 30px;\n  }\n\n  // Move up the indicators\n  .carousel-indicators {\n    bottom: 20px;\n  }\n}\n","//\n// Typography\n// --------------------------------------------------\n\n\n// Headings\n// -------------------------\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n  font-family: @headings-font-family;\n  font-weight: @headings-font-weight;\n  line-height: @headings-line-height;\n  color: @headings-color;\n\n  small,\n  .small {\n    font-weight: normal;\n    line-height: 1;\n    color: @headings-small-color;\n  }\n}\n\nh1, .h1,\nh2, .h2,\nh3, .h3 {\n  margin-top: @line-height-computed;\n  margin-bottom: (@line-height-computed / 2);\n\n  small,\n  .small {\n    font-size: 65%;\n  }\n}\nh4, .h4,\nh5, .h5,\nh6, .h6 {\n  margin-top: (@line-height-computed / 2);\n  margin-bottom: (@line-height-computed / 2);\n\n  small,\n  .small {\n    font-size: 75%;\n  }\n}\n\nh1, .h1 { font-size: @font-size-h1; }\nh2, .h2 { font-size: @font-size-h2; }\nh3, .h3 { font-size: @font-size-h3; }\nh4, .h4 { font-size: @font-size-h4; }\nh5, .h5 { font-size: @font-size-h5; }\nh6, .h6 { font-size: @font-size-h6; }\n\n\n// Body text\n// -------------------------\n\np {\n  margin: 0 0 (@line-height-computed / 2);\n}\n\n.lead {\n  margin-bottom: @line-height-computed;\n  font-size: floor((@font-size-base * 1.15));\n  font-weight: 200;\n  line-height: 1.4;\n\n  @media (min-width: @screen-sm-min) {\n    font-size: (@font-size-base * 1.5);\n  }\n}\n\n\n// Emphasis & misc\n// -------------------------\n\n// Ex: 14px base font * 85% = about 12px\nsmall,\n.small  { font-size: 85%; }\n\n// Undo browser default styling\ncite    { font-style: normal; }\n\n// Alignment\n.text-left           { text-align: left; }\n.text-right          { text-align: right; }\n.text-center         { text-align: center; }\n.text-justify        { text-align: justify; }\n\n// Contextual colors\n.text-muted {\n  color: @text-muted;\n}\n.text-primary {\n  .text-emphasis-variant(@brand-primary);\n}\n.text-success {\n  .text-emphasis-variant(@state-success-text);\n}\n.text-info {\n  .text-emphasis-variant(@state-info-text);\n}\n.text-warning {\n  .text-emphasis-variant(@state-warning-text);\n}\n.text-danger {\n  .text-emphasis-variant(@state-danger-text);\n}\n\n// Contextual backgrounds\n// For now we'll leave these alongside the text classes until v4 when we can\n// safely shift things around (per SemVer rules).\n.bg-primary {\n  // Given the contrast here, this is the only class to have its color inverted\n  // automatically.\n  color: #fff;\n  .bg-variant(@brand-primary);\n}\n.bg-success {\n  .bg-variant(@state-success-bg);\n}\n.bg-info {\n  .bg-variant(@state-info-bg);\n}\n.bg-warning {\n  .bg-variant(@state-warning-bg);\n}\n.bg-danger {\n  .bg-variant(@state-danger-bg);\n}\n\n\n// Page header\n// -------------------------\n\n.page-header {\n  padding-bottom: ((@line-height-computed / 2) - 1);\n  margin: (@line-height-computed * 2) 0 @line-height-computed;\n  border-bottom: 1px solid @page-header-border-color;\n}\n\n\n// Lists\n// --------------------------------------------------\n\n// Unordered and Ordered lists\nul,\nol {\n  margin-top: 0;\n  margin-bottom: (@line-height-computed / 2);\n  ul,\n  ol {\n    margin-bottom: 0;\n  }\n}\n\n// List options\n\n// Unstyled keeps list items block level, just removes default browser padding and list-style\n.list-unstyled {\n  padding-left: 0;\n  list-style: none;\n}\n\n// Inline turns list items into inline-block\n.list-inline {\n  .list-unstyled();\n  margin-left: -5px;\n\n  > li {\n    display: inline-block;\n    padding-left: 5px;\n    padding-right: 5px;\n  }\n}\n\n// Description Lists\ndl {\n  margin-top: 0; // Remove browser default\n  margin-bottom: @line-height-computed;\n}\ndt,\ndd {\n  line-height: @line-height-base;\n}\ndt {\n  font-weight: bold;\n}\ndd {\n  margin-left: 0; // Undo browser default\n}\n\n// Horizontal description lists\n//\n// Defaults to being stacked without any of the below styles applied, until the\n// grid breakpoint is reached (default of ~768px).\n\n@media (min-width: @grid-float-breakpoint) {\n  .dl-horizontal {\n    dt {\n      float: left;\n      width: (@component-offset-horizontal - 20);\n      clear: left;\n      text-align: right;\n      .text-overflow();\n    }\n    dd {\n      margin-left: @component-offset-horizontal;\n      &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present\n    }\n  }\n}\n\n// MISC\n// ----\n\n// Abbreviations and acronyms\nabbr[title],\n// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257\nabbr[data-original-title] {\n  cursor: help;\n  border-bottom: 1px dotted @abbr-border-color;\n}\n.initialism {\n  font-size: 90%;\n  text-transform: uppercase;\n}\n\n// Blockquotes\nblockquote {\n  padding: (@line-height-computed / 2) @line-height-computed;\n  margin: 0 0 @line-height-computed;\n  font-size: @blockquote-font-size;\n  border-left: 5px solid @blockquote-border-color;\n\n  p,\n  ul,\n  ol {\n    &:last-child {\n      margin-bottom: 0;\n    }\n  }\n\n  // Note: Deprecated small and .small as of v3.1.0\n  // Context: https://github.com/twbs/bootstrap/issues/11660\n  footer,\n  small,\n  .small {\n    display: block;\n    font-size: 80%; // back to default font-size\n    line-height: @line-height-base;\n    color: @blockquote-small-color;\n\n    &:before {\n      content: '\\2014 \\00A0'; // em dash, nbsp\n    }\n  }\n}\n\n// Opposite alignment of blockquote\n//\n// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0.\n.blockquote-reverse,\nblockquote.pull-right {\n  padding-right: 15px;\n  padding-left: 0;\n  border-right: 5px solid @blockquote-border-color;\n  border-left: 0;\n  text-align: right;\n\n  // Account for citation\n  footer,\n  small,\n  .small {\n    &:before { content: ''; }\n    &:after {\n      content: '\\00A0 \\2014'; // nbsp, em dash\n    }\n  }\n}\n\n// Quotes\nblockquote:before,\nblockquote:after {\n  content: \"\";\n}\n\n// Addresses\naddress {\n  margin-bottom: @line-height-computed;\n  font-style: normal;\n  line-height: @line-height-base;\n}\n","//\n// Code (inline and block)\n// --------------------------------------------------\n\n\n// Inline and block code styles\ncode,\nkbd,\npre,\nsamp {\n  font-family: @font-family-monospace;\n}\n\n// Inline code\ncode {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: @code-color;\n  background-color: @code-bg;\n  white-space: nowrap;\n  border-radius: @border-radius-base;\n}\n\n// User input typically entered via keyboard\nkbd {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: @kbd-color;\n  background-color: @kbd-bg;\n  border-radius: @border-radius-small;\n  box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);\n}\n\n// Blocks of code\npre {\n  display: block;\n  padding: ((@line-height-computed - 1) / 2);\n  margin: 0 0 (@line-height-computed / 2);\n  font-size: (@font-size-base - 1); // 14px to 13px\n  line-height: @line-height-base;\n  word-break: break-all;\n  word-wrap: break-word;\n  color: @pre-color;\n  background-color: @pre-bg;\n  border: 1px solid @pre-border-color;\n  border-radius: @border-radius-base;\n\n  // Account for some code outputs that place code tags in pre tags\n  code {\n    padding: 0;\n    font-size: inherit;\n    color: inherit;\n    white-space: pre-wrap;\n    background-color: transparent;\n    border-radius: 0;\n  }\n}\n\n// Enable scrollable blocks of code\n.pre-scrollable {\n  max-height: @pre-scrollable-max-height;\n  overflow-y: scroll;\n}\n","//\n// Grid system\n// --------------------------------------------------\n\n\n// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n.container {\n  .container-fixed();\n\n  @media (min-width: @screen-sm-min) {\n    width: @container-sm;\n  }\n  @media (min-width: @screen-md-min) {\n    width: @container-md;\n  }\n  @media (min-width: @screen-lg-min) {\n    width: @container-lg;\n  }\n}\n\n\n// Fluid container\n//\n// Utilizes the mixin meant for fixed width containers, but without any defined\n// width for fluid, full width layouts.\n\n.container-fluid {\n  .container-fixed();\n}\n\n\n// Row\n//\n// Rows contain and clear the floats of your columns.\n\n.row {\n  .make-row();\n}\n\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n.make-grid-columns();\n\n\n// Extra small grid\n//\n// Columns, offsets, pushes, and pulls for extra small devices like\n// smartphones.\n\n.make-grid(xs);\n\n\n// Small grid\n//\n// Columns, offsets, pushes, and pulls for the small device range, from phones\n// to tablets.\n\n@media (min-width: @screen-sm-min) {\n  .make-grid(sm);\n}\n\n\n// Medium grid\n//\n// Columns, offsets, pushes, and pulls for the desktop device range.\n\n@media (min-width: @screen-md-min) {\n  .make-grid(md);\n}\n\n\n// Large grid\n//\n// Columns, offsets, pushes, and pulls for the large desktop device range.\n\n@media (min-width: @screen-lg-min) {\n  .make-grid(lg);\n}\n","//\n// Tables\n// --------------------------------------------------\n\n\ntable {\n  max-width: 100%;\n  background-color: @table-bg;\n}\nth {\n  text-align: left;\n}\n\n\n// Baseline styles\n\n.table {\n  width: 100%;\n  margin-bottom: @line-height-computed;\n  // Cells\n  > thead,\n  > tbody,\n  > tfoot {\n    > tr {\n      > th,\n      > td {\n        padding: @table-cell-padding;\n        line-height: @line-height-base;\n        vertical-align: top;\n        border-top: 1px solid @table-border-color;\n      }\n    }\n  }\n  // Bottom align for column headings\n  > thead > tr > th {\n    vertical-align: bottom;\n    border-bottom: 2px solid @table-border-color;\n  }\n  // Remove top border from thead by default\n  > caption + thead,\n  > colgroup + thead,\n  > thead:first-child {\n    > tr:first-child {\n      > th,\n      > td {\n        border-top: 0;\n      }\n    }\n  }\n  // Account for multiple tbody instances\n  > tbody + tbody {\n    border-top: 2px solid @table-border-color;\n  }\n\n  // Nesting\n  .table {\n    background-color: @body-bg;\n  }\n}\n\n\n// Condensed table w/ half padding\n\n.table-condensed {\n  > thead,\n  > tbody,\n  > tfoot {\n    > tr {\n      > th,\n      > td {\n        padding: @table-condensed-cell-padding;\n      }\n    }\n  }\n}\n\n\n// Bordered version\n//\n// Add borders all around the table and between all the columns.\n\n.table-bordered {\n  border: 1px solid @table-border-color;\n  > thead,\n  > tbody,\n  > tfoot {\n    > tr {\n      > th,\n      > td {\n        border: 1px solid @table-border-color;\n      }\n    }\n  }\n  > thead > tr {\n    > th,\n    > td {\n      border-bottom-width: 2px;\n    }\n  }\n}\n\n\n// Zebra-striping\n//\n// Default zebra-stripe styles (alternating gray and transparent backgrounds)\n\n.table-striped {\n  > tbody > tr:nth-child(odd) {\n    > td,\n    > th {\n      background-color: @table-bg-accent;\n    }\n  }\n}\n\n\n// Hover effect\n//\n// Placed here since it has to come after the potential zebra striping\n\n.table-hover {\n  > tbody > tr:hover {\n    > td,\n    > th {\n      background-color: @table-bg-hover;\n    }\n  }\n}\n\n\n// Table cell sizing\n//\n// Reset default table behavior\n\ntable col[class*=\"col-\"] {\n  position: static; // Prevent border hiding in Firefox and IE9/10 (see https://github.com/twbs/bootstrap/issues/11623)\n  float: none;\n  display: table-column;\n}\ntable {\n  td,\n  th {\n    &[class*=\"col-\"] {\n      position: static; // Prevent border hiding in Firefox and IE9/10 (see https://github.com/twbs/bootstrap/issues/11623)\n      float: none;\n      display: table-cell;\n    }\n  }\n}\n\n\n// Table backgrounds\n//\n// Exact selectors below required to override `.table-striped` and prevent\n// inheritance to nested tables.\n\n// Generate the contextual variants\n.table-row-variant(active; @table-bg-active);\n.table-row-variant(success; @state-success-bg);\n.table-row-variant(info; @state-info-bg);\n.table-row-variant(warning; @state-warning-bg);\n.table-row-variant(danger; @state-danger-bg);\n\n\n// Responsive tables\n//\n// Wrap your tables in `.table-responsive` and we'll make them mobile friendly\n// by enabling horizontal scrolling. Only applies <768px. Everything above that\n// will display normally.\n\n@media (max-width: @screen-xs-max) {\n  .table-responsive {\n    width: 100%;\n    margin-bottom: (@line-height-computed * 0.75);\n    overflow-y: hidden;\n    overflow-x: scroll;\n    -ms-overflow-style: -ms-autohiding-scrollbar;\n    border: 1px solid @table-border-color;\n    -webkit-overflow-scrolling: touch;\n\n    // Tighten up spacing\n    > .table {\n      margin-bottom: 0;\n\n      // Ensure the content doesn't wrap\n      > thead,\n      > tbody,\n      > tfoot {\n        > tr {\n          > th,\n          > td {\n            white-space: nowrap;\n          }\n        }\n      }\n    }\n\n    // Special overrides for the bordered tables\n    > .table-bordered {\n      border: 0;\n\n      // Nuke the appropriate borders so that the parent can handle them\n      > thead,\n      > tbody,\n      > tfoot {\n        > tr {\n          > th:first-child,\n          > td:first-child {\n            border-left: 0;\n          }\n          > th:last-child,\n          > td:last-child {\n            border-right: 0;\n          }\n        }\n      }\n\n      // Only nuke the last row's bottom-border in `tbody` and `tfoot` since\n      // chances are there will be only one `tr` in a `thead` and that would\n      // remove the border altogether.\n      > tbody,\n      > tfoot {\n        > tr:last-child {\n          > th,\n          > td {\n            border-bottom: 0;\n          }\n        }\n      }\n\n    }\n  }\n}\n","//\n// Forms\n// --------------------------------------------------\n\n\n// Normalize non-controls\n//\n// Restyle and baseline non-control form elements.\n\nfieldset {\n  padding: 0;\n  margin: 0;\n  border: 0;\n  // Chrome and Firefox set a `min-width: -webkit-min-content;` on fieldsets,\n  // so we reset that to ensure it behaves more like a standard block element.\n  // See https://github.com/twbs/bootstrap/issues/12359.\n  min-width: 0;\n}\n\nlegend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: @line-height-computed;\n  font-size: (@font-size-base * 1.5);\n  line-height: inherit;\n  color: @legend-color;\n  border: 0;\n  border-bottom: 1px solid @legend-border-color;\n}\n\nlabel {\n  display: inline-block;\n  margin-bottom: 5px;\n  font-weight: bold;\n}\n\n\n// Normalize form controls\n//\n// While most of our form styles require extra classes, some basic normalization\n// is required to ensure optimum display with or without those classes to better\n// address browser inconsistencies.\n\n// Override content-box in Normalize (* isn't specific enough)\ninput[type=\"search\"] {\n  .box-sizing(border-box);\n}\n\n// Position radios and checkboxes better\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  margin: 4px 0 0;\n  margin-top: 1px \\9; /* IE8-9 */\n  line-height: normal;\n}\n\n// Set the height of file controls to match text inputs\ninput[type=\"file\"] {\n  display: block;\n}\n\n// Make range inputs behave like textual form controls\ninput[type=\"range\"] {\n  display: block;\n  width: 100%;\n}\n\n// Make multiple select elements height not fixed\nselect[multiple],\nselect[size] {\n  height: auto;\n}\n\n// Focus for file, radio, and checkbox\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n  .tab-focus();\n}\n\n// Adjust output element\noutput {\n  display: block;\n  padding-top: (@padding-base-vertical + 1);\n  font-size: @font-size-base;\n  line-height: @line-height-base;\n  color: @input-color;\n}\n\n\n// Common form controls\n//\n// Shared size and type resets for form controls. Apply `.form-control` to any\n// of the following form controls:\n//\n// select\n// textarea\n// input[type=\"text\"]\n// input[type=\"password\"]\n// input[type=\"datetime\"]\n// input[type=\"datetime-local\"]\n// input[type=\"date\"]\n// input[type=\"month\"]\n// input[type=\"time\"]\n// input[type=\"week\"]\n// input[type=\"number\"]\n// input[type=\"email\"]\n// input[type=\"url\"]\n// input[type=\"search\"]\n// input[type=\"tel\"]\n// input[type=\"color\"]\n\n.form-control {\n  display: block;\n  width: 100%;\n  height: @input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border)\n  padding: @padding-base-vertical @padding-base-horizontal;\n  font-size: @font-size-base;\n  line-height: @line-height-base;\n  color: @input-color;\n  background-color: @input-bg;\n  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n  border: 1px solid @input-border;\n  border-radius: @input-border-radius;\n  .box-shadow(inset 0 1px 1px rgba(0,0,0,.075));\n  .transition(~\"border-color ease-in-out .15s, box-shadow ease-in-out .15s\");\n\n  // Customize the `:focus` state to imitate native WebKit styles.\n  .form-control-focus();\n\n  // Placeholder\n  .placeholder();\n\n  // Disabled and read-only inputs\n  //\n  // HTML5 says that controls under a fieldset > legend:first-child won't be\n  // disabled if the fieldset is disabled. Due to implementation difficulty, we\n  // don't honor that edge case; we style them as disabled anyway.\n  &[disabled],\n  &[readonly],\n  fieldset[disabled] & {\n    cursor: not-allowed;\n    background-color: @input-bg-disabled;\n    opacity: 1; // iOS fix for unreadable disabled content\n  }\n\n  // Reset height for `textarea`s\n  textarea& {\n    height: auto;\n  }\n}\n\n\n// Search inputs in iOS\n//\n// This overrides the extra rounded corners on search inputs in iOS so that our\n// `.form-control` class can properly style them. Note that this cannot simply\n// be added to `.form-control` as it's not specific enough. For details, see\n// https://github.com/twbs/bootstrap/issues/11586.\n\ninput[type=\"search\"] {\n  -webkit-appearance: none;\n}\n\n\n// Special styles for iOS date input\n//\n// In Mobile Safari, date inputs require a pixel line-height that matches the\n// given height of the input.\n\ninput[type=\"date\"] {\n  line-height: @input-height-base;\n}\n\n\n// Form groups\n//\n// Designed to help with the organization and spacing of vertical forms. For\n// horizontal forms, use the predefined grid classes.\n\n.form-group {\n  margin-bottom: 15px;\n}\n\n\n// Checkboxes and radios\n//\n// Indent the labels to position radios/checkboxes as hanging controls.\n\n.radio,\n.checkbox {\n  display: block;\n  min-height: @line-height-computed; // clear the floating input if there is no label text\n  margin-top: 10px;\n  margin-bottom: 10px;\n  padding-left: 20px;\n  label {\n    display: inline;\n    font-weight: normal;\n    cursor: pointer;\n  }\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n  float: left;\n  margin-left: -20px;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n  margin-top: -5px; // Move up sibling radios or checkboxes for tighter spacing\n}\n\n// Radios and checkboxes on same line\n.radio-inline,\n.checkbox-inline {\n  display: inline-block;\n  padding-left: 20px;\n  margin-bottom: 0;\n  vertical-align: middle;\n  font-weight: normal;\n  cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n  margin-top: 0;\n  margin-left: 10px; // space out consecutive inline controls\n}\n\n// Apply same disabled cursor tweak as for inputs\n//\n// Note: Neither radios nor checkboxes can be readonly.\ninput[type=\"radio\"],\ninput[type=\"checkbox\"],\n.radio,\n.radio-inline,\n.checkbox,\n.checkbox-inline {\n  &[disabled],\n  fieldset[disabled] & {\n    cursor: not-allowed;\n  }\n}\n\n\n// Form control sizing\n//\n// Build on `.form-control` with modifier classes to decrease or increase the\n// height and font-size of form controls.\n\n.input-sm {\n  .input-size(@input-height-small; @padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n\n.input-lg {\n  .input-size(@input-height-large; @padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);\n}\n\n\n// Form control feedback states\n//\n// Apply contextual and semantic states to individual form controls.\n\n.has-feedback {\n  // Enable absolute positioning\n  position: relative;\n\n  // Ensure icons don't overlap text\n  .form-control {\n    padding-right: (@input-height-base * 1.25);\n  }\n\n  // Feedback icon (requires .glyphicon classes)\n  .form-control-feedback {\n    position: absolute;\n    top: (@line-height-computed + 5); // Height of the `label` and its margin\n    right: 0;\n    display: block;\n    width: @input-height-base;\n    height: @input-height-base;\n    line-height: @input-height-base;\n    text-align: center;\n  }\n}\n\n// Feedback states\n.has-success {\n  .form-control-validation(@state-success-text; @state-success-text; @state-success-bg);\n}\n.has-warning {\n  .form-control-validation(@state-warning-text; @state-warning-text; @state-warning-bg);\n}\n.has-error {\n  .form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg);\n}\n\n\n// Static form control text\n//\n// Apply class to a `p` element to make any string of text align with labels in\n// a horizontal form layout.\n\n.form-control-static {\n  margin-bottom: 0; // Remove default margin from `p`\n}\n\n\n// Help text\n//\n// Apply to any element you wish to create light text for placement immediately\n// below a form control. Use for general help, formatting, or instructional text.\n\n.help-block {\n  display: block; // account for any element using help-block\n  margin-top: 5px;\n  margin-bottom: 10px;\n  color: lighten(@text-color, 25%); // lighten the text some for contrast\n}\n\n\n\n// Inline forms\n//\n// Make forms appear inline(-block) by adding the `.form-inline` class. Inline\n// forms begin stacked on extra small (mobile) devices and then go inline when\n// viewports reach <768px.\n//\n// Requires wrapping inputs and labels with `.form-group` for proper display of\n// default HTML form controls and our custom form controls (e.g., input groups).\n//\n// Heads up! This is mixin-ed into `.navbar-form` in navbars.less.\n\n.form-inline {\n\n  // Kick in the inline\n  @media (min-width: @screen-sm-min) {\n    // Inline-block all the things for \"inline\"\n    .form-group {\n      display: inline-block;\n      margin-bottom: 0;\n      vertical-align: middle;\n    }\n\n    // In navbar-form, allow folks to *not* use `.form-group`\n    .form-control {\n      display: inline-block;\n      width: auto; // Prevent labels from stacking above inputs in `.form-group`\n      vertical-align: middle;\n    }\n    // Input groups need that 100% width though\n    .input-group > .form-control {\n      width: 100%;\n    }\n\n    .control-label {\n      margin-bottom: 0;\n      vertical-align: middle;\n    }\n\n    // Remove default margin on radios/checkboxes that were used for stacking, and\n    // then undo the floating of radios and checkboxes to match (which also avoids\n    // a bug in WebKit: https://github.com/twbs/bootstrap/issues/1969).\n    .radio,\n    .checkbox {\n      display: inline-block;\n      margin-top: 0;\n      margin-bottom: 0;\n      padding-left: 0;\n      vertical-align: middle;\n    }\n    .radio input[type=\"radio\"],\n    .checkbox input[type=\"checkbox\"] {\n      float: none;\n      margin-left: 0;\n    }\n\n    // Validation states\n    //\n    // Reposition the icon because it's now within a grid column and columns have\n    // `position: relative;` on them. Also accounts for the grid gutter padding.\n    .has-feedback .form-control-feedback {\n      top: 0;\n    }\n  }\n}\n\n\n// Horizontal forms\n//\n// Horizontal forms are built on grid classes and allow you to create forms with\n// labels on the left and inputs on the right.\n\n.form-horizontal {\n\n  // Consistent vertical alignment of labels, radios, and checkboxes\n  .control-label,\n  .radio,\n  .checkbox,\n  .radio-inline,\n  .checkbox-inline {\n    margin-top: 0;\n    margin-bottom: 0;\n    padding-top: (@padding-base-vertical + 1); // Default padding plus a border\n  }\n  // Account for padding we're adding to ensure the alignment and of help text\n  // and other content below items\n  .radio,\n  .checkbox {\n    min-height: (@line-height-computed + (@padding-base-vertical + 1));\n  }\n\n  // Make form groups behave like rows\n  .form-group {\n    .make-row();\n  }\n\n  .form-control-static {\n    padding-top: (@padding-base-vertical + 1);\n  }\n\n  // Only right align form labels here when the columns stop stacking\n  @media (min-width: @screen-sm-min) {\n    .control-label {\n      text-align: right;\n    }\n  }\n\n  // Validation states\n  //\n  // Reposition the icon because it's now within a grid column and columns have\n  // `position: relative;` on them. Also accounts for the grid gutter padding.\n  .has-feedback .form-control-feedback {\n    top: 0;\n    right: (@grid-gutter-width / 2);\n  }\n}\n","//\n// Buttons\n// --------------------------------------------------\n\n\n// Base styles\n// --------------------------------------------------\n\n.btn {\n  display: inline-block;\n  margin-bottom: 0; // For input.btn\n  font-weight: @btn-font-weight;\n  text-align: center;\n  vertical-align: middle;\n  cursor: pointer;\n  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n  border: 1px solid transparent;\n  white-space: nowrap;\n  .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @border-radius-base);\n  .user-select(none);\n\n  &,\n  &:active,\n  &.active {\n    &:focus {\n      .tab-focus();\n    }\n  }\n\n  &:hover,\n  &:focus {\n    color: @btn-default-color;\n    text-decoration: none;\n  }\n\n  &:active,\n  &.active {\n    outline: 0;\n    background-image: none;\n    .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n  }\n\n  &.disabled,\n  &[disabled],\n  fieldset[disabled] & {\n    cursor: not-allowed;\n    pointer-events: none; // Future-proof disabling of clicks\n    .opacity(.65);\n    .box-shadow(none);\n  }\n}\n\n\n// Alternate buttons\n// --------------------------------------------------\n\n.btn-default {\n  .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border);\n}\n.btn-primary {\n  .button-variant(@btn-primary-color; @btn-primary-bg; @btn-primary-border);\n}\n// Success appears as green\n.btn-success {\n  .button-variant(@btn-success-color; @btn-success-bg; @btn-success-border);\n}\n// Info appears as blue-green\n.btn-info {\n  .button-variant(@btn-info-color; @btn-info-bg; @btn-info-border);\n}\n// Warning appears as orange\n.btn-warning {\n  .button-variant(@btn-warning-color; @btn-warning-bg; @btn-warning-border);\n}\n// Danger and error appear as red\n.btn-danger {\n  .button-variant(@btn-danger-color; @btn-danger-bg; @btn-danger-border);\n}\n\n\n// Link buttons\n// -------------------------\n\n// Make a button look and behave like a link\n.btn-link {\n  color: @link-color;\n  font-weight: normal;\n  cursor: pointer;\n  border-radius: 0;\n\n  &,\n  &:active,\n  &[disabled],\n  fieldset[disabled] & {\n    background-color: transparent;\n    .box-shadow(none);\n  }\n  &,\n  &:hover,\n  &:focus,\n  &:active {\n    border-color: transparent;\n  }\n  &:hover,\n  &:focus {\n    color: @link-hover-color;\n    text-decoration: underline;\n    background-color: transparent;\n  }\n  &[disabled],\n  fieldset[disabled] & {\n    &:hover,\n    &:focus {\n      color: @btn-link-disabled-color;\n      text-decoration: none;\n    }\n  }\n}\n\n\n// Button Sizes\n// --------------------------------------------------\n\n.btn-lg {\n  // line-height: ensure even-numbered height of button next to large input\n  .button-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);\n}\n.btn-sm {\n  // line-height: ensure proper height of button next to small input\n  .button-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n.btn-xs {\n  .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n\n\n// Block button\n// --------------------------------------------------\n\n.btn-block {\n  display: block;\n  width: 100%;\n  padding-left: 0;\n  padding-right: 0;\n}\n\n// Vertically space out multiple block buttons\n.btn-block + .btn-block {\n  margin-top: 5px;\n}\n\n// Specificity overrides\ninput[type=\"submit\"],\ninput[type=\"reset\"],\ninput[type=\"button\"] {\n  &.btn-block {\n    width: 100%;\n  }\n}\n","//\n// Button groups\n// --------------------------------------------------\n\n// Make the div behave like a button\n.btn-group,\n.btn-group-vertical {\n  position: relative;\n  display: inline-block;\n  vertical-align: middle; // match .btn alignment given font-size hack above\n  > .btn {\n    position: relative;\n    float: left;\n    // Bring the \"active\" button to the front\n    &:hover,\n    &:focus,\n    &:active,\n    &.active {\n      z-index: 2;\n    }\n    &:focus {\n      // Remove focus outline when dropdown JS adds it after closing the menu\n      outline: none;\n    }\n  }\n}\n\n// Prevent double borders when buttons are next to each other\n.btn-group {\n  .btn + .btn,\n  .btn + .btn-group,\n  .btn-group + .btn,\n  .btn-group + .btn-group {\n    margin-left: -1px;\n  }\n}\n\n// Optional: Group multiple button groups together for a toolbar\n.btn-toolbar {\n  margin-left: -5px; // Offset the first child's margin\n  &:extend(.clearfix all);\n\n  .btn-group,\n  .input-group {\n    float: left;\n  }\n  > .btn,\n  > .btn-group,\n  > .input-group {\n    margin-left: 5px;\n  }\n}\n\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n  border-radius: 0;\n}\n\n// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match\n.btn-group > .btn:first-child {\n  margin-left: 0;\n  &:not(:last-child):not(.dropdown-toggle) {\n    .border-right-radius(0);\n  }\n}\n// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n  .border-left-radius(0);\n}\n\n// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group)\n.btn-group > .btn-group {\n  float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group > .btn-group:first-child {\n  > .btn:last-child,\n  > .dropdown-toggle {\n    .border-right-radius(0);\n  }\n}\n.btn-group > .btn-group:last-child > .btn:first-child {\n  .border-left-radius(0);\n}\n\n// On active and open, don't show outline\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n  outline: 0;\n}\n\n\n// Sizing\n//\n// Remix the default button sizing classes into new ones for easier manipulation.\n\n.btn-group-xs > .btn { &:extend(.btn-xs); }\n.btn-group-sm > .btn { &:extend(.btn-sm); }\n.btn-group-lg > .btn { &:extend(.btn-lg); }\n\n\n// Split button dropdowns\n// ----------------------\n\n// Give the line between buttons some depth\n.btn-group > .btn + .dropdown-toggle {\n  padding-left: 8px;\n  padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n  padding-left: 12px;\n  padding-right: 12px;\n}\n\n// The clickable button for toggling the menu\n// Remove the gradient and set the same inset shadow as the :active state\n.btn-group.open .dropdown-toggle {\n  .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n\n  // Show no shadow for `.btn-link` since it has no other button styles.\n  &.btn-link {\n    .box-shadow(none);\n  }\n}\n\n\n// Reposition the caret\n.btn .caret {\n  margin-left: 0;\n}\n// Carets in other button sizes\n.btn-lg .caret {\n  border-width: @caret-width-large @caret-width-large 0;\n  border-bottom-width: 0;\n}\n// Upside down carets for .dropup\n.dropup .btn-lg .caret {\n  border-width: 0 @caret-width-large @caret-width-large;\n}\n\n\n// Vertical button groups\n// ----------------------\n\n.btn-group-vertical {\n  > .btn,\n  > .btn-group,\n  > .btn-group > .btn {\n    display: block;\n    float: none;\n    width: 100%;\n    max-width: 100%;\n  }\n\n  // Clear floats so dropdown menus can be properly placed\n  > .btn-group {\n    &:extend(.clearfix all);\n    > .btn {\n      float: none;\n    }\n  }\n\n  > .btn + .btn,\n  > .btn + .btn-group,\n  > .btn-group + .btn,\n  > .btn-group + .btn-group {\n    margin-top: -1px;\n    margin-left: 0;\n  }\n}\n\n.btn-group-vertical > .btn {\n  &:not(:first-child):not(:last-child) {\n    border-radius: 0;\n  }\n  &:first-child:not(:last-child) {\n    border-top-right-radius: @border-radius-base;\n    .border-bottom-radius(0);\n  }\n  &:last-child:not(:first-child) {\n    border-bottom-left-radius: @border-radius-base;\n    .border-top-radius(0);\n  }\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) {\n  > .btn:last-child,\n  > .dropdown-toggle {\n    .border-bottom-radius(0);\n  }\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  .border-top-radius(0);\n}\n\n\n\n// Justified button groups\n// ----------------------\n\n.btn-group-justified {\n  display: table;\n  width: 100%;\n  table-layout: fixed;\n  border-collapse: separate;\n  > .btn,\n  > .btn-group {\n    float: none;\n    display: table-cell;\n    width: 1%;\n  }\n  > .btn-group .btn {\n    width: 100%;\n  }\n}\n\n\n// Checkbox and radio options\n[data-toggle=\"buttons\"] > .btn > input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn > input[type=\"checkbox\"] {\n  display: none;\n}\n","//\n// Component animations\n// --------------------------------------------------\n\n// Heads up!\n//\n// We don't use the `.opacity()` mixin here since it causes a bug with text\n// fields in IE7-8. Source: https://github.com/twitter/bootstrap/pull/3552.\n\n.fade {\n  opacity: 0;\n  .transition(opacity .15s linear);\n  &.in {\n    opacity: 1;\n  }\n}\n\n.collapse {\n  display: none;\n  &.in {\n    display: block;\n  }\n}\n.collapsing {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  .transition(height .35s ease);\n}\n","//\n// Glyphicons for Bootstrap\n//\n// Since icons are fonts, they can be placed anywhere text is placed and are\n// thus automatically sized to match the surrounding child. To use, create an\n// inline element with the appropriate classes, like so:\n//\n//  Star\n\n// Import the fonts\n@font-face {\n  font-family: 'Glyphicons Halflings';\n  src: ~\"url('@{icon-font-path}@{icon-font-name}.eot')\";\n  src: ~\"url('@{icon-font-path}@{icon-font-name}.eot?#iefix') format('embedded-opentype')\",\n       ~\"url('@{icon-font-path}@{icon-font-name}.woff') format('woff')\",\n       ~\"url('@{icon-font-path}@{icon-font-name}.ttf') format('truetype')\",\n       ~\"url('@{icon-font-path}@{icon-font-name}.svg#@{icon-font-svg-id}') format('svg')\";\n}\n\n// Catchall baseclass\n.glyphicon {\n  position: relative;\n  top: 1px;\n  display: inline-block;\n  font-family: 'Glyphicons Halflings';\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\n// Individual icons\n.glyphicon-asterisk               { &:before { content: \"\\2a\"; } }\n.glyphicon-plus                   { &:before { content: \"\\2b\"; } }\n.glyphicon-euro                   { &:before { content: \"\\20ac\"; } }\n.glyphicon-minus                  { &:before { content: \"\\2212\"; } }\n.glyphicon-cloud                  { &:before { content: \"\\2601\"; } }\n.glyphicon-envelope               { &:before { content: \"\\2709\"; } }\n.glyphicon-pencil                 { &:before { content: \"\\270f\"; } }\n.glyphicon-glass                  { &:before { content: \"\\e001\"; } }\n.glyphicon-music                  { &:before { content: \"\\e002\"; } }\n.glyphicon-search                 { &:before { content: \"\\e003\"; } }\n.glyphicon-heart                  { &:before { content: \"\\e005\"; } }\n.glyphicon-star                   { &:before { content: \"\\e006\"; } }\n.glyphicon-star-empty             { &:before { content: \"\\e007\"; } }\n.glyphicon-user                   { &:before { content: \"\\e008\"; } }\n.glyphicon-film                   { &:before { content: \"\\e009\"; } }\n.glyphicon-th-large               { &:before { content: \"\\e010\"; } }\n.glyphicon-th                     { &:before { content: \"\\e011\"; } }\n.glyphicon-th-list                { &:before { content: \"\\e012\"; } }\n.glyphicon-ok                     { &:before { content: \"\\e013\"; } }\n.glyphicon-remove                 { &:before { content: \"\\e014\"; } }\n.glyphicon-zoom-in                { &:before { content: \"\\e015\"; } }\n.glyphicon-zoom-out               { &:before { content: \"\\e016\"; } }\n.glyphicon-off                    { &:before { content: \"\\e017\"; } }\n.glyphicon-signal                 { &:before { content: \"\\e018\"; } }\n.glyphicon-cog                    { &:before { content: \"\\e019\"; } }\n.glyphicon-trash                  { &:before { content: \"\\e020\"; } }\n.glyphicon-home                   { &:before { content: \"\\e021\"; } }\n.glyphicon-file                   { &:before { content: \"\\e022\"; } }\n.glyphicon-time                   { &:before { content: \"\\e023\"; } }\n.glyphicon-road                   { &:before { content: \"\\e024\"; } }\n.glyphicon-download-alt           { &:before { content: \"\\e025\"; } }\n.glyphicon-download               { &:before { content: \"\\e026\"; } }\n.glyphicon-upload                 { &:before { content: \"\\e027\"; } }\n.glyphicon-inbox                  { &:before { content: \"\\e028\"; } }\n.glyphicon-play-circle            { &:before { content: \"\\e029\"; } }\n.glyphicon-repeat                 { &:before { content: \"\\e030\"; } }\n.glyphicon-refresh                { &:before { content: \"\\e031\"; } }\n.glyphicon-list-alt               { &:before { content: \"\\e032\"; } }\n.glyphicon-lock                   { &:before { content: \"\\e033\"; } }\n.glyphicon-flag                   { &:before { content: \"\\e034\"; } }\n.glyphicon-headphones             { &:before { content: \"\\e035\"; } }\n.glyphicon-volume-off             { &:before { content: \"\\e036\"; } }\n.glyphicon-volume-down            { &:before { content: \"\\e037\"; } }\n.glyphicon-volume-up              { &:before { content: \"\\e038\"; } }\n.glyphicon-qrcode                 { &:before { content: \"\\e039\"; } }\n.glyphicon-barcode                { &:before { content: \"\\e040\"; } }\n.glyphicon-tag                    { &:before { content: \"\\e041\"; } }\n.glyphicon-tags                   { &:before { content: \"\\e042\"; } }\n.glyphicon-book                   { &:before { content: \"\\e043\"; } }\n.glyphicon-bookmark               { &:before { content: \"\\e044\"; } }\n.glyphicon-print                  { &:before { content: \"\\e045\"; } }\n.glyphicon-camera                 { &:before { content: \"\\e046\"; } }\n.glyphicon-font                   { &:before { content: \"\\e047\"; } }\n.glyphicon-bold                   { &:before { content: \"\\e048\"; } }\n.glyphicon-italic                 { &:before { content: \"\\e049\"; } }\n.glyphicon-text-height            { &:before { content: \"\\e050\"; } }\n.glyphicon-text-width             { &:before { content: \"\\e051\"; } }\n.glyphicon-align-left             { &:before { content: \"\\e052\"; } }\n.glyphicon-align-center           { &:before { content: \"\\e053\"; } }\n.glyphicon-align-right            { &:before { content: \"\\e054\"; } }\n.glyphicon-align-justify          { &:before { content: \"\\e055\"; } }\n.glyphicon-list                   { &:before { content: \"\\e056\"; } }\n.glyphicon-indent-left            { &:before { content: \"\\e057\"; } }\n.glyphicon-indent-right           { &:before { content: \"\\e058\"; } }\n.glyphicon-facetime-video         { &:before { content: \"\\e059\"; } }\n.glyphicon-picture                { &:before { content: \"\\e060\"; } }\n.glyphicon-map-marker             { &:before { content: \"\\e062\"; } }\n.glyphicon-adjust                 { &:before { content: \"\\e063\"; } }\n.glyphicon-tint                   { &:before { content: \"\\e064\"; } }\n.glyphicon-edit                   { &:before { content: \"\\e065\"; } }\n.glyphicon-share                  { &:before { content: \"\\e066\"; } }\n.glyphicon-check                  { &:before { content: \"\\e067\"; } }\n.glyphicon-move                   { &:before { content: \"\\e068\"; } }\n.glyphicon-step-backward          { &:before { content: \"\\e069\"; } }\n.glyphicon-fast-backward          { &:before { content: \"\\e070\"; } }\n.glyphicon-backward               { &:before { content: \"\\e071\"; } }\n.glyphicon-play                   { &:before { content: \"\\e072\"; } }\n.glyphicon-pause                  { &:before { content: \"\\e073\"; } }\n.glyphicon-stop                   { &:before { content: \"\\e074\"; } }\n.glyphicon-forward                { &:before { content: \"\\e075\"; } }\n.glyphicon-fast-forward           { &:before { content: \"\\e076\"; } }\n.glyphicon-step-forward           { &:before { content: \"\\e077\"; } }\n.glyphicon-eject                  { &:before { content: \"\\e078\"; } }\n.glyphicon-chevron-left           { &:before { content: \"\\e079\"; } }\n.glyphicon-chevron-right          { &:before { content: \"\\e080\"; } }\n.glyphicon-plus-sign              { &:before { content: \"\\e081\"; } }\n.glyphicon-minus-sign             { &:before { content: \"\\e082\"; } }\n.glyphicon-remove-sign            { &:before { content: \"\\e083\"; } }\n.glyphicon-ok-sign                { &:before { content: \"\\e084\"; } }\n.glyphicon-question-sign          { &:before { content: \"\\e085\"; } }\n.glyphicon-info-sign              { &:before { content: \"\\e086\"; } }\n.glyphicon-screenshot             { &:before { content: \"\\e087\"; } }\n.glyphicon-remove-circle          { &:before { content: \"\\e088\"; } }\n.glyphicon-ok-circle              { &:before { content: \"\\e089\"; } }\n.glyphicon-ban-circle             { &:before { content: \"\\e090\"; } }\n.glyphicon-arrow-left             { &:before { content: \"\\e091\"; } }\n.glyphicon-arrow-right            { &:before { content: \"\\e092\"; } }\n.glyphicon-arrow-up               { &:before { content: \"\\e093\"; } }\n.glyphicon-arrow-down             { &:before { content: \"\\e094\"; } }\n.glyphicon-share-alt              { &:before { content: \"\\e095\"; } }\n.glyphicon-resize-full            { &:before { content: \"\\e096\"; } }\n.glyphicon-resize-small           { &:before { content: \"\\e097\"; } }\n.glyphicon-exclamation-sign       { &:before { content: \"\\e101\"; } }\n.glyphicon-gift                   { &:before { content: \"\\e102\"; } }\n.glyphicon-leaf                   { &:before { content: \"\\e103\"; } }\n.glyphicon-fire                   { &:before { content: \"\\e104\"; } }\n.glyphicon-eye-open               { &:before { content: \"\\e105\"; } }\n.glyphicon-eye-close              { &:before { content: \"\\e106\"; } }\n.glyphicon-warning-sign           { &:before { content: \"\\e107\"; } }\n.glyphicon-plane                  { &:before { content: \"\\e108\"; } }\n.glyphicon-calendar               { &:before { content: \"\\e109\"; } }\n.glyphicon-random                 { &:before { content: \"\\e110\"; } }\n.glyphicon-comment                { &:before { content: \"\\e111\"; } }\n.glyphicon-magnet                 { &:before { content: \"\\e112\"; } }\n.glyphicon-chevron-up             { &:before { content: \"\\e113\"; } }\n.glyphicon-chevron-down           { &:before { content: \"\\e114\"; } }\n.glyphicon-retweet                { &:before { content: \"\\e115\"; } }\n.glyphicon-shopping-cart          { &:before { content: \"\\e116\"; } }\n.glyphicon-folder-close           { &:before { content: \"\\e117\"; } }\n.glyphicon-folder-open            { &:before { content: \"\\e118\"; } }\n.glyphicon-resize-vertical        { &:before { content: \"\\e119\"; } }\n.glyphicon-resize-horizontal      { &:before { content: \"\\e120\"; } }\n.glyphicon-hdd                    { &:before { content: \"\\e121\"; } }\n.glyphicon-bullhorn               { &:before { content: \"\\e122\"; } }\n.glyphicon-bell                   { &:before { content: \"\\e123\"; } }\n.glyphicon-certificate            { &:before { content: \"\\e124\"; } }\n.glyphicon-thumbs-up              { &:before { content: \"\\e125\"; } }\n.glyphicon-thumbs-down            { &:before { content: \"\\e126\"; } }\n.glyphicon-hand-right             { &:before { content: \"\\e127\"; } }\n.glyphicon-hand-left              { &:before { content: \"\\e128\"; } }\n.glyphicon-hand-up                { &:before { content: \"\\e129\"; } }\n.glyphicon-hand-down              { &:before { content: \"\\e130\"; } }\n.glyphicon-circle-arrow-right     { &:before { content: \"\\e131\"; } }\n.glyphicon-circle-arrow-left      { &:before { content: \"\\e132\"; } }\n.glyphicon-circle-arrow-up        { &:before { content: \"\\e133\"; } }\n.glyphicon-circle-arrow-down      { &:before { content: \"\\e134\"; } }\n.glyphicon-globe                  { &:before { content: \"\\e135\"; } }\n.glyphicon-wrench                 { &:before { content: \"\\e136\"; } }\n.glyphicon-tasks                  { &:before { content: \"\\e137\"; } }\n.glyphicon-filter                 { &:before { content: \"\\e138\"; } }\n.glyphicon-briefcase              { &:before { content: \"\\e139\"; } }\n.glyphicon-fullscreen             { &:before { content: \"\\e140\"; } }\n.glyphicon-dashboard              { &:before { content: \"\\e141\"; } }\n.glyphicon-paperclip              { &:before { content: \"\\e142\"; } }\n.glyphicon-heart-empty            { &:before { content: \"\\e143\"; } }\n.glyphicon-link                   { &:before { content: \"\\e144\"; } }\n.glyphicon-phone                  { &:before { content: \"\\e145\"; } }\n.glyphicon-pushpin                { &:before { content: \"\\e146\"; } }\n.glyphicon-usd                    { &:before { content: \"\\e148\"; } }\n.glyphicon-gbp                    { &:before { content: \"\\e149\"; } }\n.glyphicon-sort                   { &:before { content: \"\\e150\"; } }\n.glyphicon-sort-by-alphabet       { &:before { content: \"\\e151\"; } }\n.glyphicon-sort-by-alphabet-alt   { &:before { content: \"\\e152\"; } }\n.glyphicon-sort-by-order          { &:before { content: \"\\e153\"; } }\n.glyphicon-sort-by-order-alt      { &:before { content: \"\\e154\"; } }\n.glyphicon-sort-by-attributes     { &:before { content: \"\\e155\"; } }\n.glyphicon-sort-by-attributes-alt { &:before { content: \"\\e156\"; } }\n.glyphicon-unchecked              { &:before { content: \"\\e157\"; } }\n.glyphicon-expand                 { &:before { content: \"\\e158\"; } }\n.glyphicon-collapse-down          { &:before { content: \"\\e159\"; } }\n.glyphicon-collapse-up            { &:before { content: \"\\e160\"; } }\n.glyphicon-log-in                 { &:before { content: \"\\e161\"; } }\n.glyphicon-flash                  { &:before { content: \"\\e162\"; } }\n.glyphicon-log-out                { &:before { content: \"\\e163\"; } }\n.glyphicon-new-window             { &:before { content: \"\\e164\"; } }\n.glyphicon-record                 { &:before { content: \"\\e165\"; } }\n.glyphicon-save                   { &:before { content: \"\\e166\"; } }\n.glyphicon-open                   { &:before { content: \"\\e167\"; } }\n.glyphicon-saved                  { &:before { content: \"\\e168\"; } }\n.glyphicon-import                 { &:before { content: \"\\e169\"; } }\n.glyphicon-export                 { &:before { content: \"\\e170\"; } }\n.glyphicon-send                   { &:before { content: \"\\e171\"; } }\n.glyphicon-floppy-disk            { &:before { content: \"\\e172\"; } }\n.glyphicon-floppy-saved           { &:before { content: \"\\e173\"; } }\n.glyphicon-floppy-remove          { &:before { content: \"\\e174\"; } }\n.glyphicon-floppy-save            { &:before { content: \"\\e175\"; } }\n.glyphicon-floppy-open            { &:before { content: \"\\e176\"; } }\n.glyphicon-credit-card            { &:before { content: \"\\e177\"; } }\n.glyphicon-transfer               { &:before { content: \"\\e178\"; } }\n.glyphicon-cutlery                { &:before { content: \"\\e179\"; } }\n.glyphicon-header                 { &:before { content: \"\\e180\"; } }\n.glyphicon-compressed             { &:before { content: \"\\e181\"; } }\n.glyphicon-earphone               { &:before { content: \"\\e182\"; } }\n.glyphicon-phone-alt              { &:before { content: \"\\e183\"; } }\n.glyphicon-tower                  { &:before { content: \"\\e184\"; } }\n.glyphicon-stats                  { &:before { content: \"\\e185\"; } }\n.glyphicon-sd-video               { &:before { content: \"\\e186\"; } }\n.glyphicon-hd-video               { &:before { content: \"\\e187\"; } }\n.glyphicon-subtitles              { &:before { content: \"\\e188\"; } }\n.glyphicon-sound-stereo           { &:before { content: \"\\e189\"; } }\n.glyphicon-sound-dolby            { &:before { content: \"\\e190\"; } }\n.glyphicon-sound-5-1              { &:before { content: \"\\e191\"; } }\n.glyphicon-sound-6-1              { &:before { content: \"\\e192\"; } }\n.glyphicon-sound-7-1              { &:before { content: \"\\e193\"; } }\n.glyphicon-copyright-mark         { &:before { content: \"\\e194\"; } }\n.glyphicon-registration-mark      { &:before { content: \"\\e195\"; } }\n.glyphicon-cloud-download         { &:before { content: \"\\e197\"; } }\n.glyphicon-cloud-upload           { &:before { content: \"\\e198\"; } }\n.glyphicon-tree-conifer           { &:before { content: \"\\e199\"; } }\n.glyphicon-tree-deciduous         { &:before { content: \"\\e200\"; } }\n","//\n// Dropdown menus\n// --------------------------------------------------\n\n\n// Dropdown arrow/caret\n.caret {\n  display: inline-block;\n  width: 0;\n  height: 0;\n  margin-left: 2px;\n  vertical-align: middle;\n  border-top:   @caret-width-base solid;\n  border-right: @caret-width-base solid transparent;\n  border-left:  @caret-width-base solid transparent;\n}\n\n// The dropdown wrapper (div)\n.dropdown {\n  position: relative;\n}\n\n// Prevent the focus on the dropdown toggle when closing dropdowns\n.dropdown-toggle:focus {\n  outline: 0;\n}\n\n// The dropdown menu (ul)\n.dropdown-menu {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  z-index: @zindex-dropdown;\n  display: none; // none by default, but block on \"open\" of the menu\n  float: left;\n  min-width: 160px;\n  padding: 5px 0;\n  margin: 2px 0 0; // override default ul\n  list-style: none;\n  font-size: @font-size-base;\n  background-color: @dropdown-bg;\n  border: 1px solid @dropdown-fallback-border; // IE8 fallback\n  border: 1px solid @dropdown-border;\n  border-radius: @border-radius-base;\n  .box-shadow(0 6px 12px rgba(0,0,0,.175));\n  background-clip: padding-box;\n\n  // Aligns the dropdown menu to right\n  //\n  // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]`\n  &.pull-right {\n    right: 0;\n    left: auto;\n  }\n\n  // Dividers (basically an hr) within the dropdown\n  .divider {\n    .nav-divider(@dropdown-divider-bg);\n  }\n\n  // Links within the dropdown menu\n  > li > a {\n    display: block;\n    padding: 3px 20px;\n    clear: both;\n    font-weight: normal;\n    line-height: @line-height-base;\n    color: @dropdown-link-color;\n    white-space: nowrap; // prevent links from randomly breaking onto new lines\n  }\n}\n\n// Hover/Focus state\n.dropdown-menu > li > a {\n  &:hover,\n  &:focus {\n    text-decoration: none;\n    color: @dropdown-link-hover-color;\n    background-color: @dropdown-link-hover-bg;\n  }\n}\n\n// Active state\n.dropdown-menu > .active > a {\n  &,\n  &:hover,\n  &:focus {\n    color: @dropdown-link-active-color;\n    text-decoration: none;\n    outline: 0;\n    background-color: @dropdown-link-active-bg;\n  }\n}\n\n// Disabled state\n//\n// Gray out text and ensure the hover/focus state remains gray\n\n.dropdown-menu > .disabled > a {\n  &,\n  &:hover,\n  &:focus {\n    color: @dropdown-link-disabled-color;\n  }\n}\n// Nuke hover/focus effects\n.dropdown-menu > .disabled > a {\n  &:hover,\n  &:focus {\n    text-decoration: none;\n    background-color: transparent;\n    background-image: none; // Remove CSS gradient\n    .reset-filter();\n    cursor: not-allowed;\n  }\n}\n\n// Open state for the dropdown\n.open {\n  // Show the menu\n  > .dropdown-menu {\n    display: block;\n  }\n\n  // Remove the outline when :focus is triggered\n  > a {\n    outline: 0;\n  }\n}\n\n// Menu positioning\n//\n// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown\n// menu with the parent.\n.dropdown-menu-right {\n  left: auto; // Reset the default from `.dropdown-menu`\n  right: 0;\n}\n// With v3, we enabled auto-flipping if you have a dropdown within a right\n// aligned nav component. To enable the undoing of that, we provide an override\n// to restore the default dropdown menu alignment.\n//\n// This is only for left-aligning a dropdown menu within a `.navbar-right` or\n// `.pull-right` nav component.\n.dropdown-menu-left {\n  left: 0;\n  right: auto;\n}\n\n// Dropdown section headers\n.dropdown-header {\n  display: block;\n  padding: 3px 20px;\n  font-size: @font-size-small;\n  line-height: @line-height-base;\n  color: @dropdown-header-color;\n}\n\n// Backdrop to catch body clicks on mobile, etc.\n.dropdown-backdrop {\n  position: fixed;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  top: 0;\n  z-index: (@zindex-dropdown - 10);\n}\n\n// Right aligned dropdowns\n.pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n\n// Allow for dropdowns to go bottom up (aka, dropup-menu)\n//\n// Just add .dropup after the standard .dropdown class and you're set, bro.\n// TODO: abstract this so that the navbar fixed styles are not placed here?\n\n.dropup,\n.navbar-fixed-bottom .dropdown {\n  // Reverse the caret\n  .caret {\n    border-top: 0;\n    border-bottom: @caret-width-base solid;\n    content: \"\";\n  }\n  // Different positioning for bottom up menu\n  .dropdown-menu {\n    top: auto;\n    bottom: 100%;\n    margin-bottom: 1px;\n  }\n}\n\n\n// Component alignment\n//\n// Reiterate per navbar.less and the modified component alignment there.\n\n@media (min-width: @grid-float-breakpoint) {\n  .navbar-right {\n    .dropdown-menu {\n      .dropdown-menu-right();\n    }\n    // Necessary for overrides of the default right aligned menu.\n    // Will remove come v4 in all likelihood.\n    .dropdown-menu-left {\n      .dropdown-menu-left();\n    }\n  }\n}\n\n","//\n// Input groups\n// --------------------------------------------------\n\n// Base styles\n// -------------------------\n.input-group {\n  position: relative; // For dropdowns\n  display: table;\n  border-collapse: separate; // prevent input groups from inheriting border styles from table cells when placed within a table\n\n  // Undo padding and float of grid classes\n  &[class*=\"col-\"] {\n    float: none;\n    padding-left: 0;\n    padding-right: 0;\n  }\n\n  .form-control {\n    // Ensure that the input is always above the *appended* addon button for\n    // proper border colors.\n    position: relative;\n    z-index: 2;\n\n    // IE9 fubars the placeholder attribute in text inputs and the arrows on\n    // select elements in input groups. To fix it, we float the input. Details:\n    // https://github.com/twbs/bootstrap/issues/11561#issuecomment-28936855\n    float: left;\n\n    width: 100%;\n    margin-bottom: 0;\n  }\n}\n\n// Sizing options\n//\n// Remix the default form control sizing classes into new ones for easier\n// manipulation.\n\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn { .input-lg(); }\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn { .input-sm(); }\n\n\n// Display as table-cell\n// -------------------------\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n  display: table-cell;\n\n  &:not(:first-child):not(:last-child) {\n    border-radius: 0;\n  }\n}\n// Addon and addon wrapper for buttons\n.input-group-addon,\n.input-group-btn {\n  width: 1%;\n  white-space: nowrap;\n  vertical-align: middle; // Match the inputs\n}\n\n// Text input groups\n// -------------------------\n.input-group-addon {\n  padding: @padding-base-vertical @padding-base-horizontal;\n  font-size: @font-size-base;\n  font-weight: normal;\n  line-height: 1;\n  color: @input-color;\n  text-align: center;\n  background-color: @input-group-addon-bg;\n  border: 1px solid @input-group-addon-border-color;\n  border-radius: @border-radius-base;\n\n  // Sizing\n  &.input-sm {\n    padding: @padding-small-vertical @padding-small-horizontal;\n    font-size: @font-size-small;\n    border-radius: @border-radius-small;\n  }\n  &.input-lg {\n    padding: @padding-large-vertical @padding-large-horizontal;\n    font-size: @font-size-large;\n    border-radius: @border-radius-large;\n  }\n\n  // Nuke default margins from checkboxes and radios to vertically center within.\n  input[type=\"radio\"],\n  input[type=\"checkbox\"] {\n    margin-top: 0;\n  }\n}\n\n// Reset rounded corners\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n  .border-right-radius(0);\n}\n.input-group-addon:first-child {\n  border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n  .border-left-radius(0);\n}\n.input-group-addon:last-child {\n  border-left: 0;\n}\n\n// Button input groups\n// -------------------------\n.input-group-btn {\n  position: relative;\n  // Jankily prevent input button groups from wrapping with `white-space` and\n  // `font-size` in combination with `inline-block` on buttons.\n  font-size: 0;\n  white-space: nowrap;\n\n  // Negative margin for spacing, position for bringing hovered/focused/actived\n  // element above the siblings.\n  > .btn {\n    position: relative;\n    + .btn {\n      margin-left: -1px;\n    }\n    // Bring the \"active\" button to the front\n    &:hover,\n    &:focus,\n    &:active {\n      z-index: 2;\n    }\n  }\n\n  // Negative margin to only have a 1px border between the two\n  &:first-child {\n    > .btn,\n    > .btn-group {\n      margin-right: -1px;\n    }\n  }\n  &:last-child {\n    > .btn,\n    > .btn-group {\n      margin-left: -1px;\n    }\n  }\n}\n","//\n// Navs\n// --------------------------------------------------\n\n\n// Base class\n// --------------------------------------------------\n\n.nav {\n  margin-bottom: 0;\n  padding-left: 0; // Override default ul/ol\n  list-style: none;\n  &:extend(.clearfix all);\n\n  > li {\n    position: relative;\n    display: block;\n\n    > a {\n      position: relative;\n      display: block;\n      padding: @nav-link-padding;\n      &:hover,\n      &:focus {\n        text-decoration: none;\n        background-color: @nav-link-hover-bg;\n      }\n    }\n\n    // Disabled state sets text to gray and nukes hover/tab effects\n    &.disabled > a {\n      color: @nav-disabled-link-color;\n\n      &:hover,\n      &:focus {\n        color: @nav-disabled-link-hover-color;\n        text-decoration: none;\n        background-color: transparent;\n        cursor: not-allowed;\n      }\n    }\n  }\n\n  // Open dropdowns\n  .open > a {\n    &,\n    &:hover,\n    &:focus {\n      background-color: @nav-link-hover-bg;\n      border-color: @link-color;\n    }\n  }\n\n  // Nav dividers (deprecated with v3.0.1)\n  //\n  // This should have been removed in v3 with the dropping of `.nav-list`, but\n  // we missed it. We don't currently support this anywhere, but in the interest\n  // of maintaining backward compatibility in case you use it, it's deprecated.\n  .nav-divider {\n    .nav-divider();\n  }\n\n  // Prevent IE8 from misplacing imgs\n  //\n  // See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989\n  > li > a > img {\n    max-width: none;\n  }\n}\n\n\n// Tabs\n// -------------------------\n\n// Give the tabs something to sit on\n.nav-tabs {\n  border-bottom: 1px solid @nav-tabs-border-color;\n  > li {\n    float: left;\n    // Make the list-items overlay the bottom border\n    margin-bottom: -1px;\n\n    // Actual tabs (as links)\n    > a {\n      margin-right: 2px;\n      line-height: @line-height-base;\n      border: 1px solid transparent;\n      border-radius: @border-radius-base @border-radius-base 0 0;\n      &:hover {\n        border-color: @nav-tabs-link-hover-border-color @nav-tabs-link-hover-border-color @nav-tabs-border-color;\n      }\n    }\n\n    // Active state, and its :hover to override normal :hover\n    &.active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @nav-tabs-active-link-hover-color;\n        background-color: @nav-tabs-active-link-hover-bg;\n        border: 1px solid @nav-tabs-active-link-hover-border-color;\n        border-bottom-color: transparent;\n        cursor: default;\n      }\n    }\n  }\n  // pulling this in mainly for less shorthand\n  &.nav-justified {\n    .nav-justified();\n    .nav-tabs-justified();\n  }\n}\n\n\n// Pills\n// -------------------------\n.nav-pills {\n  > li {\n    float: left;\n\n    // Links rendered as pills\n    > a {\n      border-radius: @nav-pills-border-radius;\n    }\n    + li {\n      margin-left: 2px;\n    }\n\n    // Active state\n    &.active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @nav-pills-active-link-hover-color;\n        background-color: @nav-pills-active-link-hover-bg;\n      }\n    }\n  }\n}\n\n\n// Stacked pills\n.nav-stacked {\n  > li {\n    float: none;\n    + li {\n      margin-top: 2px;\n      margin-left: 0; // no need for this gap between nav items\n    }\n  }\n}\n\n\n// Nav variations\n// --------------------------------------------------\n\n// Justified nav links\n// -------------------------\n\n.nav-justified {\n  width: 100%;\n\n  > li {\n    float: none;\n     > a {\n      text-align: center;\n      margin-bottom: 5px;\n    }\n  }\n\n  > .dropdown .dropdown-menu {\n    top: auto;\n    left: auto;\n  }\n\n  @media (min-width: @screen-sm-min) {\n    > li {\n      display: table-cell;\n      width: 1%;\n      > a {\n        margin-bottom: 0;\n      }\n    }\n  }\n}\n\n// Move borders to anchors instead of bottom of list\n//\n// Mixin for adding on top the shared `.nav-justified` styles for our tabs\n.nav-tabs-justified {\n  border-bottom: 0;\n\n  > li > a {\n    // Override margin from .nav-tabs\n    margin-right: 0;\n    border-radius: @border-radius-base;\n  }\n\n  > .active > a,\n  > .active > a:hover,\n  > .active > a:focus {\n    border: 1px solid @nav-tabs-justified-link-border-color;\n  }\n\n  @media (min-width: @screen-sm-min) {\n    > li > a {\n      border-bottom: 1px solid @nav-tabs-justified-link-border-color;\n      border-radius: @border-radius-base @border-radius-base 0 0;\n    }\n    > .active > a,\n    > .active > a:hover,\n    > .active > a:focus {\n      border-bottom-color: @nav-tabs-justified-active-link-border-color;\n    }\n  }\n}\n\n\n// Tabbable tabs\n// -------------------------\n\n// Hide tabbable panes to start, show them when `.active`\n.tab-content {\n  > .tab-pane {\n    display: none;\n  }\n  > .active {\n    display: block;\n  }\n}\n\n\n// Dropdowns\n// -------------------------\n\n// Specific dropdowns\n.nav-tabs .dropdown-menu {\n  // make dropdown border overlap tab border\n  margin-top: -1px;\n  // Remove the top rounded corners here since there is a hard edge above the menu\n  .border-top-radius(0);\n}\n","//\n// Navbars\n// --------------------------------------------------\n\n\n// Wrapper and base class\n//\n// Provide a static navbar from which we expand to create full-width, fixed, and\n// other navbar variations.\n\n.navbar {\n  position: relative;\n  min-height: @navbar-height; // Ensure a navbar always shows (e.g., without a .navbar-brand in collapsed mode)\n  margin-bottom: @navbar-margin-bottom;\n  border: 1px solid transparent;\n\n  // Prevent floats from breaking the navbar\n  &:extend(.clearfix all);\n\n  @media (min-width: @grid-float-breakpoint) {\n    border-radius: @navbar-border-radius;\n  }\n}\n\n\n// Navbar heading\n//\n// Groups `.navbar-brand` and `.navbar-toggle` into a single component for easy\n// styling of responsive aspects.\n\n.navbar-header {\n  &:extend(.clearfix all);\n\n  @media (min-width: @grid-float-breakpoint) {\n    float: left;\n  }\n}\n\n\n// Navbar collapse (body)\n//\n// Group your navbar content into this for easy collapsing and expanding across\n// various device sizes. By default, this content is collapsed when <768px, but\n// will expand past that for a horizontal display.\n//\n// To start (on mobile devices) the navbar links, forms, and buttons are stacked\n// vertically and include a `max-height` to overflow in case you have too much\n// content for the user's viewport.\n\n.navbar-collapse {\n  max-height: @navbar-collapse-max-height;\n  overflow-x: visible;\n  padding-right: @navbar-padding-horizontal;\n  padding-left:  @navbar-padding-horizontal;\n  border-top: 1px solid transparent;\n  box-shadow: inset 0 1px 0 rgba(255,255,255,.1);\n  &:extend(.clearfix all);\n  -webkit-overflow-scrolling: touch;\n\n  &.in {\n    overflow-y: auto;\n  }\n\n  @media (min-width: @grid-float-breakpoint) {\n    width: auto;\n    border-top: 0;\n    box-shadow: none;\n\n    &.collapse {\n      display: block !important;\n      height: auto !important;\n      padding-bottom: 0; // Override default setting\n      overflow: visible !important;\n    }\n\n    &.in {\n      overflow-y: visible;\n    }\n\n    // Undo the collapse side padding for navbars with containers to ensure\n    // alignment of right-aligned contents.\n    .navbar-fixed-top &,\n    .navbar-static-top &,\n    .navbar-fixed-bottom & {\n      padding-left: 0;\n      padding-right: 0;\n    }\n  }\n}\n\n\n// Both navbar header and collapse\n//\n// When a container is present, change the behavior of the header and collapse.\n\n.container,\n.container-fluid {\n  > .navbar-header,\n  > .navbar-collapse {\n    margin-right: -@navbar-padding-horizontal;\n    margin-left:  -@navbar-padding-horizontal;\n\n    @media (min-width: @grid-float-breakpoint) {\n      margin-right: 0;\n      margin-left:  0;\n    }\n  }\n}\n\n\n//\n// Navbar alignment options\n//\n// Display the navbar across the entirety of the page or fixed it to the top or\n// bottom of the page.\n\n// Static top (unfixed, but 100% wide) navbar\n.navbar-static-top {\n  z-index: @zindex-navbar;\n  border-width: 0 0 1px;\n\n  @media (min-width: @grid-float-breakpoint) {\n    border-radius: 0;\n  }\n}\n\n// Fix the top/bottom navbars when screen real estate supports it\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  position: fixed;\n  right: 0;\n  left: 0;\n  z-index: @zindex-navbar-fixed;\n\n  // Undo the rounded corners\n  @media (min-width: @grid-float-breakpoint) {\n    border-radius: 0;\n  }\n}\n.navbar-fixed-top {\n  top: 0;\n  border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n  bottom: 0;\n  margin-bottom: 0; // override .navbar defaults\n  border-width: 1px 0 0;\n}\n\n\n// Brand/project name\n\n.navbar-brand {\n  float: left;\n  padding: @navbar-padding-vertical @navbar-padding-horizontal;\n  font-size: @font-size-large;\n  line-height: @line-height-computed;\n  height: @navbar-height;\n\n  &:hover,\n  &:focus {\n    text-decoration: none;\n  }\n\n  @media (min-width: @grid-float-breakpoint) {\n    .navbar > .container &,\n    .navbar > .container-fluid & {\n      margin-left: -@navbar-padding-horizontal;\n    }\n  }\n}\n\n\n// Navbar toggle\n//\n// Custom button for toggling the `.navbar-collapse`, powered by the collapse\n// JavaScript plugin.\n\n.navbar-toggle {\n  position: relative;\n  float: right;\n  margin-right: @navbar-padding-horizontal;\n  padding: 9px 10px;\n  .navbar-vertical-align(34px);\n  background-color: transparent;\n  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n  border: 1px solid transparent;\n  border-radius: @border-radius-base;\n\n  // We remove the `outline` here, but later compensate by attaching `:hover`\n  // styles to `:focus`.\n  &:focus {\n    outline: none;\n  }\n\n  // Bars\n  .icon-bar {\n    display: block;\n    width: 22px;\n    height: 2px;\n    border-radius: 1px;\n  }\n  .icon-bar + .icon-bar {\n    margin-top: 4px;\n  }\n\n  @media (min-width: @grid-float-breakpoint) {\n    display: none;\n  }\n}\n\n\n// Navbar nav links\n//\n// Builds on top of the `.nav` components with its own modifier class to make\n// the nav the full height of the horizontal nav (above 768px).\n\n.navbar-nav {\n  margin: (@navbar-padding-vertical / 2) -@navbar-padding-horizontal;\n\n  > li > a {\n    padding-top:    10px;\n    padding-bottom: 10px;\n    line-height: @line-height-computed;\n  }\n\n  @media (max-width: @grid-float-breakpoint-max) {\n    // Dropdowns get custom display when collapsed\n    .open .dropdown-menu {\n      position: static;\n      float: none;\n      width: auto;\n      margin-top: 0;\n      background-color: transparent;\n      border: 0;\n      box-shadow: none;\n      > li > a,\n      .dropdown-header {\n        padding: 5px 15px 5px 25px;\n      }\n      > li > a {\n        line-height: @line-height-computed;\n        &:hover,\n        &:focus {\n          background-image: none;\n        }\n      }\n    }\n  }\n\n  // Uncollapse the nav\n  @media (min-width: @grid-float-breakpoint) {\n    float: left;\n    margin: 0;\n\n    > li {\n      float: left;\n      > a {\n        padding-top:    @navbar-padding-vertical;\n        padding-bottom: @navbar-padding-vertical;\n      }\n    }\n\n    &.navbar-right:last-child {\n      margin-right: -@navbar-padding-horizontal;\n    }\n  }\n}\n\n\n// Component alignment\n//\n// Repurpose the pull utilities as their own navbar utilities to avoid specificity\n// issues with parents and chaining. Only do this when the navbar is uncollapsed\n// though so that navbar contents properly stack and align in mobile.\n\n@media (min-width: @grid-float-breakpoint) {\n  .navbar-left  { .pull-left(); }\n  .navbar-right { .pull-right(); }\n}\n\n\n// Navbar form\n//\n// Extension of the `.form-inline` with some extra flavor for optimum display in\n// our navbars.\n\n.navbar-form {\n  margin-left: -@navbar-padding-horizontal;\n  margin-right: -@navbar-padding-horizontal;\n  padding: 10px @navbar-padding-horizontal;\n  border-top: 1px solid transparent;\n  border-bottom: 1px solid transparent;\n  @shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);\n  .box-shadow(@shadow);\n\n  // Mixin behavior for optimum display\n  .form-inline();\n\n  .form-group {\n    @media (max-width: @grid-float-breakpoint-max) {\n      margin-bottom: 5px;\n    }\n  }\n\n  // Vertically center in expanded, horizontal navbar\n  .navbar-vertical-align(@input-height-base);\n\n  // Undo 100% width for pull classes\n  @media (min-width: @grid-float-breakpoint) {\n    width: auto;\n    border: 0;\n    margin-left: 0;\n    margin-right: 0;\n    padding-top: 0;\n    padding-bottom: 0;\n    .box-shadow(none);\n\n    // Outdent the form if last child to line up with content down the page\n    &.navbar-right:last-child {\n      margin-right: -@navbar-padding-horizontal;\n    }\n  }\n}\n\n\n// Dropdown menus\n\n// Menu position and menu carets\n.navbar-nav > li > .dropdown-menu {\n  margin-top: 0;\n  .border-top-radius(0);\n}\n// Menu position and menu caret support for dropups via extra dropup class\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n  .border-bottom-radius(0);\n}\n\n\n// Buttons in navbars\n//\n// Vertically center a button within a navbar (when *not* in a form).\n\n.navbar-btn {\n  .navbar-vertical-align(@input-height-base);\n\n  &.btn-sm {\n    .navbar-vertical-align(@input-height-small);\n  }\n  &.btn-xs {\n    .navbar-vertical-align(22);\n  }\n}\n\n\n// Text in navbars\n//\n// Add a class to make any element properly align itself vertically within the navbars.\n\n.navbar-text {\n  .navbar-vertical-align(@line-height-computed);\n\n  @media (min-width: @grid-float-breakpoint) {\n    float: left;\n    margin-left: @navbar-padding-horizontal;\n    margin-right: @navbar-padding-horizontal;\n\n    // Outdent the form if last child to line up with content down the page\n    &.navbar-right:last-child {\n      margin-right: 0;\n    }\n  }\n}\n\n// Alternate navbars\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n  background-color: @navbar-default-bg;\n  border-color: @navbar-default-border;\n\n  .navbar-brand {\n    color: @navbar-default-brand-color;\n    &:hover,\n    &:focus {\n      color: @navbar-default-brand-hover-color;\n      background-color: @navbar-default-brand-hover-bg;\n    }\n  }\n\n  .navbar-text {\n    color: @navbar-default-color;\n  }\n\n  .navbar-nav {\n    > li > a {\n      color: @navbar-default-link-color;\n\n      &:hover,\n      &:focus {\n        color: @navbar-default-link-hover-color;\n        background-color: @navbar-default-link-hover-bg;\n      }\n    }\n    > .active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-default-link-active-color;\n        background-color: @navbar-default-link-active-bg;\n      }\n    }\n    > .disabled > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-default-link-disabled-color;\n        background-color: @navbar-default-link-disabled-bg;\n      }\n    }\n  }\n\n  .navbar-toggle {\n    border-color: @navbar-default-toggle-border-color;\n    &:hover,\n    &:focus {\n      background-color: @navbar-default-toggle-hover-bg;\n    }\n    .icon-bar {\n      background-color: @navbar-default-toggle-icon-bar-bg;\n    }\n  }\n\n  .navbar-collapse,\n  .navbar-form {\n    border-color: @navbar-default-border;\n  }\n\n  // Dropdown menu items\n  .navbar-nav {\n    // Remove background color from open dropdown\n    > .open > a {\n      &,\n      &:hover,\n      &:focus {\n        background-color: @navbar-default-link-active-bg;\n        color: @navbar-default-link-active-color;\n      }\n    }\n\n    @media (max-width: @grid-float-breakpoint-max) {\n      // Dropdowns get custom display when collapsed\n      .open .dropdown-menu {\n        > li > a {\n          color: @navbar-default-link-color;\n          &:hover,\n          &:focus {\n            color: @navbar-default-link-hover-color;\n            background-color: @navbar-default-link-hover-bg;\n          }\n        }\n        > .active > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-default-link-active-color;\n            background-color: @navbar-default-link-active-bg;\n          }\n        }\n        > .disabled > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-default-link-disabled-color;\n            background-color: @navbar-default-link-disabled-bg;\n          }\n        }\n      }\n    }\n  }\n\n\n  // Links in navbars\n  //\n  // Add a class to ensure links outside the navbar nav are colored correctly.\n\n  .navbar-link {\n    color: @navbar-default-link-color;\n    &:hover {\n      color: @navbar-default-link-hover-color;\n    }\n  }\n\n}\n\n// Inverse navbar\n\n.navbar-inverse {\n  background-color: @navbar-inverse-bg;\n  border-color: @navbar-inverse-border;\n\n  .navbar-brand {\n    color: @navbar-inverse-brand-color;\n    &:hover,\n    &:focus {\n      color: @navbar-inverse-brand-hover-color;\n      background-color: @navbar-inverse-brand-hover-bg;\n    }\n  }\n\n  .navbar-text {\n    color: @navbar-inverse-color;\n  }\n\n  .navbar-nav {\n    > li > a {\n      color: @navbar-inverse-link-color;\n\n      &:hover,\n      &:focus {\n        color: @navbar-inverse-link-hover-color;\n        background-color: @navbar-inverse-link-hover-bg;\n      }\n    }\n    > .active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-inverse-link-active-color;\n        background-color: @navbar-inverse-link-active-bg;\n      }\n    }\n    > .disabled > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-inverse-link-disabled-color;\n        background-color: @navbar-inverse-link-disabled-bg;\n      }\n    }\n  }\n\n  // Darken the responsive nav toggle\n  .navbar-toggle {\n    border-color: @navbar-inverse-toggle-border-color;\n    &:hover,\n    &:focus {\n      background-color: @navbar-inverse-toggle-hover-bg;\n    }\n    .icon-bar {\n      background-color: @navbar-inverse-toggle-icon-bar-bg;\n    }\n  }\n\n  .navbar-collapse,\n  .navbar-form {\n    border-color: darken(@navbar-inverse-bg, 7%);\n  }\n\n  // Dropdowns\n  .navbar-nav {\n    > .open > a {\n      &,\n      &:hover,\n      &:focus {\n        background-color: @navbar-inverse-link-active-bg;\n        color: @navbar-inverse-link-active-color;\n      }\n    }\n\n    @media (max-width: @grid-float-breakpoint-max) {\n      // Dropdowns get custom display\n      .open .dropdown-menu {\n        > .dropdown-header {\n          border-color: @navbar-inverse-border;\n        }\n        .divider {\n          background-color: @navbar-inverse-border;\n        }\n        > li > a {\n          color: @navbar-inverse-link-color;\n          &:hover,\n          &:focus {\n            color: @navbar-inverse-link-hover-color;\n            background-color: @navbar-inverse-link-hover-bg;\n          }\n        }\n        > .active > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-inverse-link-active-color;\n            background-color: @navbar-inverse-link-active-bg;\n          }\n        }\n        > .disabled > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-inverse-link-disabled-color;\n            background-color: @navbar-inverse-link-disabled-bg;\n          }\n        }\n      }\n    }\n  }\n\n  .navbar-link {\n    color: @navbar-inverse-link-color;\n    &:hover {\n      color: @navbar-inverse-link-hover-color;\n    }\n  }\n\n}\n","//\n// Utility classes\n// --------------------------------------------------\n\n\n// Floats\n// -------------------------\n\n.clearfix {\n  .clearfix();\n}\n.center-block {\n  .center-block();\n}\n.pull-right {\n  float: right !important;\n}\n.pull-left {\n  float: left !important;\n}\n\n\n// Toggling content\n// -------------------------\n\n// Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1\n.hide {\n  display: none !important;\n}\n.show {\n  display: block !important;\n}\n.invisible {\n  visibility: hidden;\n}\n.text-hide {\n  .text-hide();\n}\n\n\n// Hide from screenreaders and browsers\n//\n// Credit: HTML5 Boilerplate\n\n.hidden {\n  display: none !important;\n  visibility: hidden !important;\n}\n\n\n// For Affix plugin\n// -------------------------\n\n.affix {\n  position: fixed;\n}\n","//\n// Breadcrumbs\n// --------------------------------------------------\n\n\n.breadcrumb {\n  padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal;\n  margin-bottom: @line-height-computed;\n  list-style: none;\n  background-color: @breadcrumb-bg;\n  border-radius: @border-radius-base;\n\n  > li {\n    display: inline-block;\n\n    + li:before {\n      content: \"@{breadcrumb-separator}\\00a0\"; // Unicode space added since inline-block means non-collapsing white-space\n      padding: 0 5px;\n      color: @breadcrumb-color;\n    }\n  }\n\n  > .active {\n    color: @breadcrumb-active-color;\n  }\n}\n","//\n// Pagination (multiple pages)\n// --------------------------------------------------\n.pagination {\n  display: inline-block;\n  padding-left: 0;\n  margin: @line-height-computed 0;\n  border-radius: @border-radius-base;\n\n  > li {\n    display: inline; // Remove list-style and block-level defaults\n    > a,\n    > span {\n      position: relative;\n      float: left; // Collapse white-space\n      padding: @padding-base-vertical @padding-base-horizontal;\n      line-height: @line-height-base;\n      text-decoration: none;\n      color: @pagination-color;\n      background-color: @pagination-bg;\n      border: 1px solid @pagination-border;\n      margin-left: -1px;\n    }\n    &:first-child {\n      > a,\n      > span {\n        margin-left: 0;\n        .border-left-radius(@border-radius-base);\n      }\n    }\n    &:last-child {\n      > a,\n      > span {\n        .border-right-radius(@border-radius-base);\n      }\n    }\n  }\n\n  > li > a,\n  > li > span {\n    &:hover,\n    &:focus {\n      color: @pagination-hover-color;\n      background-color: @pagination-hover-bg;\n      border-color: @pagination-hover-border;\n    }\n  }\n\n  > .active > a,\n  > .active > span {\n    &,\n    &:hover,\n    &:focus {\n      z-index: 2;\n      color: @pagination-active-color;\n      background-color: @pagination-active-bg;\n      border-color: @pagination-active-border;\n      cursor: default;\n    }\n  }\n\n  > .disabled {\n    > span,\n    > span:hover,\n    > span:focus,\n    > a,\n    > a:hover,\n    > a:focus {\n      color: @pagination-disabled-color;\n      background-color: @pagination-disabled-bg;\n      border-color: @pagination-disabled-border;\n      cursor: not-allowed;\n    }\n  }\n}\n\n// Sizing\n// --------------------------------------------------\n\n// Large\n.pagination-lg {\n  .pagination-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @border-radius-large);\n}\n\n// Small\n.pagination-sm {\n  .pagination-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @border-radius-small);\n}\n","//\n// Pager pagination\n// --------------------------------------------------\n\n\n.pager {\n  padding-left: 0;\n  margin: @line-height-computed 0;\n  list-style: none;\n  text-align: center;\n  &:extend(.clearfix all);\n  li {\n    display: inline;\n    > a,\n    > span {\n      display: inline-block;\n      padding: 5px 14px;\n      background-color: @pager-bg;\n      border: 1px solid @pager-border;\n      border-radius: @pager-border-radius;\n    }\n\n    > a:hover,\n    > a:focus {\n      text-decoration: none;\n      background-color: @pager-hover-bg;\n    }\n  }\n\n  .next {\n    > a,\n    > span {\n      float: right;\n    }\n  }\n\n  .previous {\n    > a,\n    > span {\n      float: left;\n    }\n  }\n\n  .disabled {\n    > a,\n    > a:hover,\n    > a:focus,\n    > span {\n      color: @pager-disabled-color;\n      background-color: @pager-bg;\n      cursor: not-allowed;\n    }\n  }\n\n}\n","//\n// Labels\n// --------------------------------------------------\n\n.label {\n  display: inline;\n  padding: .2em .6em .3em;\n  font-size: 75%;\n  font-weight: bold;\n  line-height: 1;\n  color: @label-color;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: baseline;\n  border-radius: .25em;\n\n  // Add hover effects, but only for links\n  &[href] {\n    &:hover,\n    &:focus {\n      color: @label-link-hover-color;\n      text-decoration: none;\n      cursor: pointer;\n    }\n  }\n\n  // Empty labels collapse automatically (not available in IE8)\n  &:empty {\n    display: none;\n  }\n\n  // Quick fix for labels in buttons\n  .btn & {\n    position: relative;\n    top: -1px;\n  }\n}\n\n// Colors\n// Contextual variations (linked labels get darker on :hover)\n\n.label-default {\n  .label-variant(@label-default-bg);\n}\n\n.label-primary {\n  .label-variant(@label-primary-bg);\n}\n\n.label-success {\n  .label-variant(@label-success-bg);\n}\n\n.label-info {\n  .label-variant(@label-info-bg);\n}\n\n.label-warning {\n  .label-variant(@label-warning-bg);\n}\n\n.label-danger {\n  .label-variant(@label-danger-bg);\n}\n","//\n// Badges\n// --------------------------------------------------\n\n\n// Base classes\n.badge {\n  display: inline-block;\n  min-width: 10px;\n  padding: 3px 7px;\n  font-size: @font-size-small;\n  font-weight: @badge-font-weight;\n  color: @badge-color;\n  line-height: @badge-line-height;\n  vertical-align: baseline;\n  white-space: nowrap;\n  text-align: center;\n  background-color: @badge-bg;\n  border-radius: @badge-border-radius;\n\n  // Empty badges collapse automatically (not available in IE8)\n  &:empty {\n    display: none;\n  }\n\n  // Quick fix for badges in buttons\n  .btn & {\n    position: relative;\n    top: -1px;\n  }\n  .btn-xs & {\n    top: 0;\n    padding: 1px 5px;\n  }\n}\n\n// Hover state, but only for links\na.badge {\n  &:hover,\n  &:focus {\n    color: @badge-link-hover-color;\n    text-decoration: none;\n    cursor: pointer;\n  }\n}\n\n// Account for counters in navs\na.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n  color: @badge-active-color;\n  background-color: @badge-active-bg;\n}\n.nav-pills > li > a > .badge {\n  margin-left: 3px;\n}\n","//\n// Jumbotron\n// --------------------------------------------------\n\n\n.jumbotron {\n  padding: @jumbotron-padding;\n  margin-bottom: @jumbotron-padding;\n  color: @jumbotron-color;\n  background-color: @jumbotron-bg;\n\n  h1,\n  .h1 {\n    color: @jumbotron-heading-color;\n  }\n  p {\n    margin-bottom: (@jumbotron-padding / 2);\n    font-size: @jumbotron-font-size;\n    font-weight: 200;\n  }\n\n  .container & {\n    border-radius: @border-radius-large; // Only round corners at higher resolutions if contained in a container\n  }\n\n  .container {\n    max-width: 100%;\n  }\n\n  @media screen and (min-width: @screen-sm-min) {\n    padding-top:    (@jumbotron-padding * 1.6);\n    padding-bottom: (@jumbotron-padding * 1.6);\n\n    .container & {\n      padding-left:  (@jumbotron-padding * 2);\n      padding-right: (@jumbotron-padding * 2);\n    }\n\n    h1,\n    .h1 {\n      font-size: (@font-size-base * 4.5);\n    }\n  }\n}\n","//\n// Alerts\n// --------------------------------------------------\n\n\n// Base styles\n// -------------------------\n\n.alert {\n  padding: @alert-padding;\n  margin-bottom: @line-height-computed;\n  border: 1px solid transparent;\n  border-radius: @alert-border-radius;\n\n  // Headings for larger alerts\n  h4 {\n    margin-top: 0;\n    // Specified for the h4 to prevent conflicts of changing @headings-color\n    color: inherit;\n  }\n  // Provide class for links that match alerts\n  .alert-link {\n    font-weight: @alert-link-font-weight;\n  }\n\n  // Improve alignment and spacing of inner content\n  > p,\n  > ul {\n    margin-bottom: 0;\n  }\n  > p + p {\n    margin-top: 5px;\n  }\n}\n\n// Dismissable alerts\n//\n// Expand the right padding and account for the close button's positioning.\n\n.alert-dismissable {\n padding-right: (@alert-padding + 20);\n\n  // Adjust close link position\n  .close {\n    position: relative;\n    top: -2px;\n    right: -21px;\n    color: inherit;\n  }\n}\n\n// Alternate styles\n//\n// Generate contextual modifier classes for colorizing the alert.\n\n.alert-success {\n  .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text);\n}\n.alert-info {\n  .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text);\n}\n.alert-warning {\n  .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);\n}\n.alert-danger {\n  .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);\n}\n","//\n// Progress bars\n// --------------------------------------------------\n\n\n// Bar animations\n// -------------------------\n\n// WebKit\n@-webkit-keyframes progress-bar-stripes {\n  from  { background-position: 40px 0; }\n  to    { background-position: 0 0; }\n}\n\n// Spec and IE10+\n@keyframes progress-bar-stripes {\n  from  { background-position: 40px 0; }\n  to    { background-position: 0 0; }\n}\n\n\n\n// Bar itself\n// -------------------------\n\n// Outer container\n.progress {\n  overflow: hidden;\n  height: @line-height-computed;\n  margin-bottom: @line-height-computed;\n  background-color: @progress-bg;\n  border-radius: @border-radius-base;\n  .box-shadow(inset 0 1px 2px rgba(0,0,0,.1));\n}\n\n// Bar of progress\n.progress-bar {\n  float: left;\n  width: 0%;\n  height: 100%;\n  font-size: @font-size-small;\n  line-height: @line-height-computed;\n  color: @progress-bar-color;\n  text-align: center;\n  background-color: @progress-bar-bg;\n  .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));\n  .transition(width .6s ease);\n}\n\n// Striped bars\n.progress-striped .progress-bar {\n  #gradient > .striped();\n  background-size: 40px 40px;\n}\n\n// Call animation for the active one\n.progress.active .progress-bar {\n  .animation(progress-bar-stripes 2s linear infinite);\n}\n\n\n\n// Variations\n// -------------------------\n\n.progress-bar-success {\n  .progress-bar-variant(@progress-bar-success-bg);\n}\n\n.progress-bar-info {\n  .progress-bar-variant(@progress-bar-info-bg);\n}\n\n.progress-bar-warning {\n  .progress-bar-variant(@progress-bar-warning-bg);\n}\n\n.progress-bar-danger {\n  .progress-bar-variant(@progress-bar-danger-bg);\n}\n","// Media objects\n// Source: http://stubbornella.org/content/?p=497\n// --------------------------------------------------\n\n\n// Common styles\n// -------------------------\n\n// Clear the floats\n.media,\n.media-body {\n  overflow: hidden;\n  zoom: 1;\n}\n\n// Proper spacing between instances of .media\n.media,\n.media .media {\n  margin-top: 15px;\n}\n.media:first-child {\n  margin-top: 0;\n}\n\n// For images and videos, set to block\n.media-object {\n  display: block;\n}\n\n// Reset margins on headings for tighter default spacing\n.media-heading {\n  margin: 0 0 5px;\n}\n\n\n// Media image alignment\n// -------------------------\n\n.media {\n  > .pull-left {\n    margin-right: 10px;\n  }\n  > .pull-right {\n    margin-left: 10px;\n  }\n}\n\n\n// Media list variation\n// -------------------------\n\n// Undo default ul/ol styles\n.media-list {\n  padding-left: 0;\n  list-style: none;\n}\n","//\n// List groups\n// --------------------------------------------------\n\n\n// Base class\n//\n// Easily usable on 
    -
    - - - - -

    - {% include "footer.html" %} - - - - - \ No newline at end of file diff --git a/ui/footer.html b/ui/footer.html deleted file mode 100644 index b15b8db9..00000000 --- a/ui/footer.html +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - -
    - - -
    - About Peace Corps  |   - Policies  |   - Important Details  |   - Help   -

    -
    -
    - - - - - - - - -

    ©2014 PeaceCrops

    - - Return to Top -
    \ No newline at end of file diff --git a/ui/forgot_password.html b/ui/forgot_password.html deleted file mode 100644 index d7d913f0..00000000 --- a/ui/forgot_password.html +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - Forget Password - - - - {% include "header.html" %} -





    - -
    - -
    - - -
    -
    -

    Forgot Password

    -

    - -
    -
    -
    -
    - -
    -
    -
    -
    - -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    -
    - -
    - -
    -
    - -
    - - -
    - - -


    - {% include "footer.html" %} - - - - - diff --git a/ui/header.html b/ui/header.html deleted file mode 100644 index ba6aa5df..00000000 --- a/ui/header.html +++ /dev/null @@ -1,29 +0,0 @@ - - - diff --git a/ui/helpPC.html b/ui/helpPC.html deleted file mode 100644 index 41614046..00000000 --- a/ui/helpPC.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - Help PC - - - {% include "header.html" %} -





    -

    Here the help information about PC would be shown

    - -

















    - {% include "footer.html" %} - - - - diff --git a/ui/index.html b/ui/index.html deleted file mode 100644 index 5346f56b..00000000 --- a/ui/index.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - Welcome ! - - - - {% include "header.html" %} -





    - -
    - -
    -
    -
    -

    Log in

    -
    -

    Username :

    - -

    Password :

    - -
    - Forgot Password ? -

    -

    -

    New User ? Click here to Sign Up !

    -
    -

    -
    - -
    - -

    - {% include "footer.html" %} - - - - - diff --git a/ui/notice.html b/ui/notice.html deleted file mode 100644 index d0fccd8d..00000000 --- a/ui/notice.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - Notice - - - {% include "header.html" %} -







    -

    {{text}}

    -

    {{text1}}

    -












    - {% include "footer.html" %} - - - - diff --git a/ui/policies.html b/ui/policies.html deleted file mode 100644 index 203cb8b3..00000000 --- a/ui/policies.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - About PC - - - {% include "header.html" %} -





    -

    Here the information about policies would be shown

    - -

















    - {% include "footer.html" %} - - - - diff --git a/ui/profile.html b/ui/profile.html deleted file mode 100644 index c31bde55..00000000 --- a/ui/profile.html +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - User Profile | {{profiler.user.first_name}} - - - {% include "header.html" %} -





    - -
    -
    -

    User Profile

    -
    -
    -
    -
    -
    -
    -

    First Name : {{profiler.user.first_name}}

    -

    Last Name : {{profiler.user.last_name}}

    -

    Email Address : {{profiler.user.email}}

    -

    Mobile : {{profiler.phone}}

    -

    Gender : {{profiler.gender}}

    -

    Location : {{profiler.location}}

    - -
    -
    -
    - -

    User {{profiler.user}}

    -
    -
    - -
    -
    -

    -
    - {% if profiler.user.username == pcuser.user.username %} - - {% endif %} - -
    - - -
    -

    - {% include "footer.html" %} - - \ No newline at end of file diff --git a/ui/redirect.html b/ui/redirect.html deleted file mode 100755 index 59eeb192..00000000 --- a/ui/redirect.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/ui/reset_password.html b/ui/reset_password.html deleted file mode 100644 index f154ca2a..00000000 --- a/ui/reset_password.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - Reset Password - - - - {% include "header.html" %} -





    - -
    -
    -
    -
    - -
    -

    Reset your password


    - -
    -
    -
    -
    - -
    -
    -
    -
    - - -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - - - - - - -
    - -
    - - -
    - -



    - {% include "footer.html" %} - - - - - diff --git a/ui/signup.html b/ui/signup.html deleted file mode 100644 index 96f0c797..00000000 --- a/ui/signup.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - Sign Up - - - - {% include "header.html" %} -





    - -
    - -
    -
    -
    -

    Sign Up Form

    -
    - - - -
    - - -
    - -

    Username :

    - -

    Email id :

    - - - - -

    First name :

    - -

    Last name :

    - - - -

    Set Password :

    - -

    Confirm Password :

    -
    both passwords should match
    - -

    Phone :

    - -

    Location :

    -
    should be text
    - - - -

    -

    - -
    -

    -
    - -
    - -





    - {% include "footer.html" %} - - - - - diff --git a/ui/test.html b/ui/test.html deleted file mode 100644 index e0d91c32..00000000 --- a/ui/test.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - Test Page - - - No of worksheets {{no}} - - \ No newline at end of file diff --git a/webhub/PKG-INFO b/webhub/PKG-INFO deleted file mode 100644 index 513bf98a..00000000 --- a/webhub/PKG-INFO +++ /dev/null @@ -1,21 +0,0 @@ -Metadata-Version: 1.0 -Name: xlrd -Version: 0.9.3 -Summary: Library for developers to extract data from Microsoft Excel (tm) spreadsheet files -Home-page: http://www.python-excel.org/ -Author: John Machin -Author-email: sjmachin@lexicon.net -License: BSD -Description: Extract data from Excel spreadsheets (.xls and .xlsx, versions 2.0 onwards) on any platform. Pure Python (2.6, 2.7, 3.2+). Strong support for Excel dates. Unicode-aware. -Keywords: xls,excel,spreadsheet,workbook -Platform: Any platform -- don't need Windows -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: BSD License -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 3 -Classifier: Operating System :: OS Independent -Classifier: Topic :: Database -Classifier: Topic :: Office/Business -Classifier: Topic :: Software Development :: Libraries :: Python Modules diff --git a/webhub/README.html b/webhub/README.html deleted file mode 100644 index bbc3675f..00000000 --- a/webhub/README.html +++ /dev/null @@ -1,135 +0,0 @@ - - - - -The xlrd Module -- README - - - -

    Python package "xlrd"

    - -

    Purpose: Provide a library for developers to use to extract data - from Microsoft Excel (tm) spreadsheet files. - It is not an end-user tool. -

    -

    Author: John Machin, Lingfo Pty Ltd (sjmachin@lexicon.net) -

    -

    Licence: BSD-style (see licences.py) -

    -

    Version of xlrd: 0.7.1 -- 2009-05-31 -

    -

    Versions of Python supported: 2.6-2.7. -

    -

    External modules required: -

    -
    The package itself is pure Python with no dependencies on modules or packages - outside the standard Python distribution. -
    -
    -

    Versions of Excel supported: - 2004, 2003, XP, 2000, 97, 95, 5.0, 4.0, 3.0, 2.1, 2.0. - Support for Excel 2007 .xlsx files scheduled for version 0.7.1. -

    -

    Outside the current scope: xlrd will safely and reliably ignore any of these -if present in the file: -

    -
      -
    • Charts, Macros, Pictures, any other embedded object. WARNING: currently - this includes embedded worksheets. -
    • -
    • VBA modules -
    • -
    • Formulas (results of formula calculations are extracted, of course). -
    • -
    • Comments -
    • -
    • Hyperlinks -
    • -
    • Autofilters, advanced filters, pivot tables, conditional formatting, data validation -
    • -
    -

    Unlikely to be done: -

    -
    • Handling password-protected (encrypted) files. -
    • -
    -

    Particular emphasis (refer docs for details): -

    -
    • Operability across OS, regions, platforms -
    • -
    • Handling Excel's date problems, including the Windows / Macintosh - four-year differential. -
    • -
    • Providing access to named constants and named groups of cells (from version 0.6.0) -
    • -
    • Providing access to "visual" information: font, "number format", background, border, - alignment and protection for cells, height/width etc for rows/columns (from version 0.6.1) -
    • -
    -

    Quick start: -

    -
        import xlrd
    -    book = xlrd.open_workbook("myfile.xls")
    -    print "The number of worksheets is", book.nsheets
    -    print "Worksheet name(s):", book.sheet_names()
    -    sh = book.sheet_by_index(0)
    -    print sh.name, sh.nrows, sh.ncols
    -    print "Cell D30 is", sh.cell_value(rowx=29, colx=3)
    -    for rx in range(sh.nrows):
    -        print sh.row(rx)
    -    # Refer to docs for more details.
    -    # Feedback on API is welcomed.
    -

    -

    -

    Another quick start: This will show the first, second and last rows of each - sheet in each file: -

    - -
        OS-prompt>python PYDIR/scripts/runxlrd.py 3rows *blah*.xls
    - -

    Installation: -

    -
    • On Windows: use the installer. -
    • -
    • Any OS: Unzip the .zip file into a suitable directory, - chdir to that directory, then do "python setup.py install". -
    • -
    • If PYDIR is your Python installation directory: - the main files are in PYDIR/Lib/site-packages/xlrd - the docs are in the doc subdirectory, - and there's a sample script: PYDIR/Scripts/runxlrd.py -
    • -
    • If os.sep != "/": make the appropriate adjustments. -
    • -
    -

    Download URLs: -

    -
    • http://pypi.python.org/pypi/xlrd -
    • -
    • http://www.lexicon.net/sjmachin/xlrd.htm -
    • -
    -

    Acknowledgements: -

    -
    • This package started life as a translation from C into Python -of parts of a utility called "xlreader" developed by David Giffin. -"This product includes software developed by David Giffin <david@giffin.org>." -
    • -
    • OpenOffice.org has truly excellent documentation of the Microsoft Excel file formats -and Compound Document file format, authored by Daniel Rentz. See http://sc.openoffice.org -
    • -
    • U+5F20 U+654F: over a decade of inspiration, support, and interesting decoding opportunities. -
    • -
    • Ksenia Marasanova: sample Macintosh and non-Latin1 files, alpha testing -
    • -
    • Backporting to Python 2.1 was partially funded by Journyx - provider of -timesheet and project accounting solutions (http://journyx.com/). -
    • -
    • Provision of formatting information in version 0.6.1 was funded by Simplistix Ltd - (http://www.simplistix.co.uk/) -
    • -
    • << a growing list of names; see HISTORY.html >>: feedback, testing, test files, ... -
    - - - diff --git a/webhub/Updated Project Framework Indicator List PeaceTrack.xlsx b/webhub/Updated Project Framework Indicator List PeaceTrack.xlsx deleted file mode 100644 index a227790a..00000000 Binary files a/webhub/Updated Project Framework Indicator List PeaceTrack.xlsx and /dev/null differ diff --git a/webhub/admin.py b/webhub/admin.py index 49a181b7..ae04f024 100644 --- a/webhub/admin.py +++ b/webhub/admin.py @@ -1,21 +1,7 @@ from django.contrib import admin -from malaria.models import Post, RevPost -from peacetrack.models import * + +from malaria_web.models import Post, RevPost from webhub.models import * -admin.site.register(Pcuser) admin.site.register(Post) admin.site.register(RevPost) -admin.site.register(Region) -admin.site.register(Sector) -admin.site.register(PTPost) -admin.site.register(Project) -admin.site.register(Goal) -admin.site.register(Objective) -admin.site.register(Indicator) -admin.site.register(Output) -admin.site.register(Outcome) -admin.site.register(Activity) -admin.site.register(Measurement) -admin.site.register(Cohort) -admin.site.register(Volunteer) diff --git a/webhub/checker.py b/webhub/checker.py deleted file mode 100755 index 531d428d..00000000 --- a/webhub/checker.py +++ /dev/null @@ -1,36 +0,0 @@ -#Version : Phython/Django 2.7.6, PostgreSQL 9.3.4 -#Author : Vaibhavi Desai -#Github username : desaivaibhavi -#email : ranihaileydesai@gmail.com - -from django.http import HttpResponse -from django.utils import timezone -from webhub.models import * -from django.views.decorators.csrf import csrf_exempt -import datetime -from django.contrib.auth import authenticate, login, logout -from django.contrib.auth.models import User -from django.shortcuts import redirect -from django.db.models import Count, Min, Sum, Avg -import uuid -import jinja2 -from jinja2.ext import loopcontrols - -jinja_environ = jinja2.Environment(loader=jinja2.FileSystemLoader(['ui']), extensions=[loopcontrols]) - -#Checker function used to see if user is logged in and verified etc. Made separately instead of writing repeatedly -def check(request): - - #Check if user is logged in - if not request.user.is_authenticated(): - return HttpResponse(jinja_environ.get_template('index.html').render({"pcuser":None})) - - #Check if user has an associated rider - #(This will be false if the admin logs in) - try: - request.user.pcuser - except: - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'

    No Pcuser associated! Add a pcuser from admin

    '})) - - return None diff --git a/webhub/database.py b/webhub/database.py deleted file mode 100644 index bc3e62ae..00000000 --- a/webhub/database.py +++ /dev/null @@ -1,4 +0,0 @@ -#Version : Phython/Django 2.7.6, PostgreSQL 9.3.4 -#Author : Vaibhavi Desai -#Github username : desaivaibhavi -#email : ranihaileydesai@gmail.com \ No newline at end of file diff --git a/webhub/models.py b/webhub/models.py index 53b5997f..e69de29b 100644 --- a/webhub/models.py +++ b/webhub/models.py @@ -1,39 +0,0 @@ -from django.db import models -from django.contrib.auth.models import User - -import os - -# To update the filename of the newly uploaded photo -def update_filename(instance, filename): - path = '/vagrant/submit/media/propics/' - format = instance.user.username + ".jpg" - return os.path.join(path, format) - - - -# Django provides a table called user that stores basic user information like username, password and email id. -class Pcuser(models.Model): - #username - user = models.OneToOneField(User) - #location - location = models.CharField(max_length=300) - #phone number - phone = models.CharField(max_length=150) - #gender - gender = models.CharField(max_length=10) - #for reset_password - reset_pass = models.CharField(default="",max_length=320) - - - #path to default user image - image = models.CharField(max_length=300, default="http://i.imgur.com/dnjclWV.png") - #image - imageobj = models.ImageField(upload_to=update_filename) - - #verification status - #1 - unverified - #any other number = verification code - verified = models.CharField(max_length=100) - - def __unicode__(self): - return self.user.username diff --git a/webhub/scripts/runxlrd.py b/webhub/scripts/runxlrd.py deleted file mode 100644 index f26067e1..00000000 --- a/webhub/scripts/runxlrd.py +++ /dev/null @@ -1,414 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2005-2012 Stephen John Machin, Lingfo Pty Ltd -# This script is part of the xlrd package, which is released under a -# BSD-style licence. - -from __future__ import print_function - -cmd_doc = """ -Commands: - -2rows Print the contents of first and last row in each sheet -3rows Print the contents of first, second and last row in each sheet -bench Same as "show", but doesn't print -- for profiling -biff_count[1] Print a count of each type of BIFF record in the file -biff_dump[1] Print a dump (char and hex) of the BIFF records in the file -fonts hdr + print a dump of all font objects -hdr Mini-overview of file (no per-sheet information) -hotshot Do a hotshot profile run e.g. ... -f1 hotshot bench bigfile*.xls -labels Dump of sheet.col_label_ranges and ...row... for each sheet -name_dump Dump of each object in book.name_obj_list -names Print brief information for each NAME record -ov Overview of file -profile Like "hotshot", but uses cProfile -show Print the contents of all rows in each sheet -version[0] Print versions of xlrd and Python and exit -xfc Print "XF counts" and cell-type counts -- see code for details - -[0] means no file arg -[1] means only one file arg i.e. no glob.glob pattern -""" - -options = None -if __name__ == "__main__": - - PSYCO = 0 - - import xlrd - import sys, time, glob, traceback, gc - - from xlrd.timemachine import xrange, REPR - - - class LogHandler(object): - - def __init__(self, logfileobj): - self.logfileobj = logfileobj - self.fileheading = None - self.shown = 0 - - def setfileheading(self, fileheading): - self.fileheading = fileheading - self.shown = 0 - - def write(self, text): - if self.fileheading and not self.shown: - self.logfileobj.write(self.fileheading) - self.shown = 1 - self.logfileobj.write(text) - - null_cell = xlrd.empty_cell - - def show_row(bk, sh, rowx, colrange, printit): - if bk.ragged_rows: - colrange = range(sh.row_len(rowx)) - if not colrange: return - if printit: print() - if bk.formatting_info: - for colx, ty, val, cxfx in get_row_data(bk, sh, rowx, colrange): - if printit: - print("cell %s%d: type=%d, data: %r, xfx: %s" - % (xlrd.colname(colx), rowx+1, ty, val, cxfx)) - else: - for colx, ty, val, _unused in get_row_data(bk, sh, rowx, colrange): - if printit: - print("cell %s%d: type=%d, data: %r" % (xlrd.colname(colx), rowx+1, ty, val)) - - def get_row_data(bk, sh, rowx, colrange): - result = [] - dmode = bk.datemode - ctys = sh.row_types(rowx) - cvals = sh.row_values(rowx) - for colx in colrange: - cty = ctys[colx] - cval = cvals[colx] - if bk.formatting_info: - cxfx = str(sh.cell_xf_index(rowx, colx)) - else: - cxfx = '' - if cty == xlrd.XL_CELL_DATE: - try: - showval = xlrd.xldate_as_tuple(cval, dmode) - except xlrd.XLDateError as e: - showval = "%s:%s" % (type(e).__name__, e) - cty = xlrd.XL_CELL_ERROR - elif cty == xlrd.XL_CELL_ERROR: - showval = xlrd.error_text_from_code.get(cval, '' % cval) - else: - showval = cval - result.append((colx, cty, showval, cxfx)) - return result - - def bk_header(bk): - print() - print("BIFF version: %s; datemode: %s" - % (xlrd.biff_text_from_num[bk.biff_version], bk.datemode)) - print("codepage: %r (encoding: %s); countries: %r" - % (bk.codepage, bk.encoding, bk.countries)) - print("Last saved by: %r" % bk.user_name) - print("Number of data sheets: %d" % bk.nsheets) - print("Use mmap: %d; Formatting: %d; On demand: %d" - % (bk.use_mmap, bk.formatting_info, bk.on_demand)) - print("Ragged rows: %d" % bk.ragged_rows) - if bk.formatting_info: - print("FORMATs: %d, FONTs: %d, XFs: %d" - % (len(bk.format_list), len(bk.font_list), len(bk.xf_list))) - if not options.suppress_timing: - print("Load time: %.2f seconds (stage 1) %.2f seconds (stage 2)" - % (bk.load_time_stage_1, bk.load_time_stage_2)) - print() - - def show_fonts(bk): - print("Fonts:") - for x in xrange(len(bk.font_list)): - font = bk.font_list[x] - font.dump(header='== Index %d ==' % x, indent=4) - - def show_names(bk, dump=0): - bk_header(bk) - if bk.biff_version < 50: - print("Names not extracted in this BIFF version") - return - nlist = bk.name_obj_list - print("Name list: %d entries" % len(nlist)) - for nobj in nlist: - if dump: - nobj.dump(sys.stdout, - header="\n=== Dump of name_obj_list[%d] ===" % nobj.name_index) - else: - print("[%d]\tName:%r macro:%r scope:%d\n\tresult:%r\n" - % (nobj.name_index, nobj.name, nobj.macro, nobj.scope, nobj.result)) - - def print_labels(sh, labs, title): - if not labs:return - for rlo, rhi, clo, chi in labs: - print("%s label range %s:%s contains:" - % (title, xlrd.cellname(rlo, clo), xlrd.cellname(rhi-1, chi-1))) - for rx in xrange(rlo, rhi): - for cx in xrange(clo, chi): - print(" %s: %r" % (xlrd.cellname(rx, cx), sh.cell_value(rx, cx))) - - def show_labels(bk): - # bk_header(bk) - hdr = 0 - for shx in range(bk.nsheets): - sh = bk.sheet_by_index(shx) - clabs = sh.col_label_ranges - rlabs = sh.row_label_ranges - if clabs or rlabs: - if not hdr: - bk_header(bk) - hdr = 1 - print("sheet %d: name = %r; nrows = %d; ncols = %d" % - (shx, sh.name, sh.nrows, sh.ncols)) - print_labels(sh, clabs, 'Col') - print_labels(sh, rlabs, 'Row') - if bk.on_demand: bk.unload_sheet(shx) - - def show(bk, nshow=65535, printit=1): - bk_header(bk) - if 0: - rclist = xlrd.sheet.rc_stats.items() - rclist = sorted(rclist) - print("rc stats") - for k, v in rclist: - print("0x%04x %7d" % (k, v)) - if options.onesheet: - try: - shx = int(options.onesheet) - except ValueError: - shx = bk.sheet_by_name(options.onesheet).number - shxrange = [shx] - else: - shxrange = range(bk.nsheets) - # print("shxrange", list(shxrange)) - for shx in shxrange: - sh = bk.sheet_by_index(shx) - nrows, ncols = sh.nrows, sh.ncols - colrange = range(ncols) - anshow = min(nshow, nrows) - print("sheet %d: name = %s; nrows = %d; ncols = %d" % - (shx, REPR(sh.name), sh.nrows, sh.ncols)) - if nrows and ncols: - # Beat the bounds - for rowx in xrange(nrows): - nc = sh.row_len(rowx) - if nc: - _junk = sh.row_types(rowx)[nc-1] - _junk = sh.row_values(rowx)[nc-1] - _junk = sh.cell(rowx, nc-1) - for rowx in xrange(anshow-1): - if not printit and rowx % 10000 == 1 and rowx > 1: - print("done %d rows" % (rowx-1,)) - show_row(bk, sh, rowx, colrange, printit) - if anshow and nrows: - show_row(bk, sh, nrows-1, colrange, printit) - print() - if bk.on_demand: bk.unload_sheet(shx) - - def count_xfs(bk): - bk_header(bk) - for shx in range(bk.nsheets): - sh = bk.sheet_by_index(shx) - nrows, ncols = sh.nrows, sh.ncols - print("sheet %d: name = %r; nrows = %d; ncols = %d" % - (shx, sh.name, sh.nrows, sh.ncols)) - # Access all xfindexes to force gathering stats - type_stats = [0, 0, 0, 0, 0, 0, 0] - for rowx in xrange(nrows): - for colx in xrange(sh.row_len(rowx)): - xfx = sh.cell_xf_index(rowx, colx) - assert xfx >= 0 - cty = sh.cell_type(rowx, colx) - type_stats[cty] += 1 - print("XF stats", sh._xf_index_stats) - print("type stats", type_stats) - print() - if bk.on_demand: bk.unload_sheet(shx) - - def main(cmd_args): - import optparse - global options, PSYCO - usage = "\n%prog [options] command [input-file-patterns]\n" + cmd_doc - oparser = optparse.OptionParser(usage) - oparser.add_option( - "-l", "--logfilename", - default="", - help="contains error messages") - oparser.add_option( - "-v", "--verbosity", - type="int", default=0, - help="level of information and diagnostics provided") - oparser.add_option( - "-m", "--mmap", - type="int", default=-1, - help="1: use mmap; 0: don't use mmap; -1: accept heuristic") - oparser.add_option( - "-e", "--encoding", - default="", - help="encoding override") - oparser.add_option( - "-f", "--formatting", - type="int", default=0, - help="0 (default): no fmt info\n" - "1: fmt info (all cells)\n" - ) - oparser.add_option( - "-g", "--gc", - type="int", default=0, - help="0: auto gc enabled; 1: auto gc disabled, manual collect after each file; 2: no gc") - oparser.add_option( - "-s", "--onesheet", - default="", - help="restrict output to this sheet (name or index)") - oparser.add_option( - "-u", "--unnumbered", - action="store_true", default=0, - help="omit line numbers or offsets in biff_dump") - oparser.add_option( - "-d", "--on-demand", - action="store_true", default=0, - help="load sheets on demand instead of all at once") - oparser.add_option( - "-t", "--suppress-timing", - action="store_true", default=0, - help="don't print timings (diffs are less messy)") - oparser.add_option( - "-r", "--ragged-rows", - action="store_true", default=0, - help="open_workbook(..., ragged_rows=True)") - options, args = oparser.parse_args(cmd_args) - if len(args) == 1 and args[0] in ("version", ): - pass - elif len(args) < 2: - oparser.error("Expected at least 2 args, found %d" % len(args)) - cmd = args[0] - xlrd_version = getattr(xlrd, "__VERSION__", "unknown; before 0.5") - if cmd == 'biff_dump': - xlrd.dump(args[1], unnumbered=options.unnumbered) - sys.exit(0) - if cmd == 'biff_count': - xlrd.count_records(args[1]) - sys.exit(0) - if cmd == 'version': - print("xlrd: %s, from %s" % (xlrd_version, xlrd.__file__)) - print("Python:", sys.version) - sys.exit(0) - if options.logfilename: - logfile = LogHandler(open(options.logfilename, 'w')) - else: - logfile = sys.stdout - mmap_opt = options.mmap - mmap_arg = xlrd.USE_MMAP - if mmap_opt in (1, 0): - mmap_arg = mmap_opt - elif mmap_opt != -1: - print('Unexpected value (%r) for mmap option -- assuming default' % mmap_opt) - fmt_opt = options.formatting | (cmd in ('xfc', )) - gc_mode = options.gc - if gc_mode: - gc.disable() - for pattern in args[1:]: - for fname in glob.glob(pattern): - print("\n=== File: %s ===" % fname) - if logfile != sys.stdout: - logfile.setfileheading("\n=== File: %s ===\n" % fname) - if gc_mode == 1: - n_unreachable = gc.collect() - if n_unreachable: - print("GC before open:", n_unreachable, "unreachable objects") - if PSYCO: - import psyco - psyco.full() - PSYCO = 0 - try: - t0 = time.time() - bk = xlrd.open_workbook(fname, - verbosity=options.verbosity, logfile=logfile, - use_mmap=mmap_arg, - encoding_override=options.encoding, - formatting_info=fmt_opt, - on_demand=options.on_demand, - ragged_rows=options.ragged_rows, - ) - t1 = time.time() - if not options.suppress_timing: - print("Open took %.2f seconds" % (t1-t0,)) - except xlrd.XLRDError as e: - print("*** Open failed: %s: %s" % (type(e).__name__, e)) - continue - except KeyboardInterrupt: - print("*** KeyboardInterrupt ***") - traceback.print_exc(file=sys.stdout) - sys.exit(1) - except BaseException as e: - print("*** Open failed: %s: %s" % (type(e).__name__, e)) - traceback.print_exc(file=sys.stdout) - continue - t0 = time.time() - if cmd == 'hdr': - bk_header(bk) - elif cmd == 'ov': # OverView - show(bk, 0) - elif cmd == 'show': # all rows - show(bk) - elif cmd == '2rows': # first row and last row - show(bk, 2) - elif cmd == '3rows': # first row, 2nd row and last row - show(bk, 3) - elif cmd == 'bench': - show(bk, printit=0) - elif cmd == 'fonts': - bk_header(bk) - show_fonts(bk) - elif cmd == 'names': # named reference list - show_names(bk) - elif cmd == 'name_dump': # named reference list - show_names(bk, dump=1) - elif cmd == 'labels': - show_labels(bk) - elif cmd == 'xfc': - count_xfs(bk) - else: - print("*** Unknown command <%s>" % cmd) - sys.exit(1) - del bk - if gc_mode == 1: - n_unreachable = gc.collect() - if n_unreachable: - print("GC post cmd:", fname, "->", n_unreachable, "unreachable objects") - if not options.suppress_timing: - t1 = time.time() - print("\ncommand took %.2f seconds\n" % (t1-t0,)) - - return None - - av = sys.argv[1:] - if not av: - main(av) - firstarg = av[0].lower() - if firstarg == "hotshot": - import hotshot, hotshot.stats - av = av[1:] - prof_log_name = "XXXX.prof" - prof = hotshot.Profile(prof_log_name) - # benchtime, result = prof.runcall(main, *av) - result = prof.runcall(main, *(av, )) - print("result", repr(result)) - prof.close() - stats = hotshot.stats.load(prof_log_name) - stats.strip_dirs() - stats.sort_stats('time', 'calls') - stats.print_stats(20) - elif firstarg == "profile": - import cProfile - av = av[1:] - cProfile.run('main(av)', 'YYYY.prof') - import pstats - p = pstats.Stats('YYYY.prof') - p.strip_dirs().sort_stats('cumulative').print_stats(30) - elif firstarg == "psyco": - PSYCO = 1 - main(av[1:]) - else: - main(av) diff --git a/webhub/serializers.py b/webhub/serializers.py index 916547b4..cf198bd9 100644 --- a/webhub/serializers.py +++ b/webhub/serializers.py @@ -1,97 +1,15 @@ from django.contrib.auth.models import User -from webhub.models import * -from malaria.models import Post, RevPost -from peacetrack.models import * - from rest_framework import serializers +from profiles.models import * + + class UserSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = User fields = ('url', 'username', 'email','id') - class PcuserSerializer(serializers.ModelSerializer): class Meta: model = Pcuser fields = ('user', 'location', 'phone', 'gender','id') - -class PostSerializer(serializers.ModelSerializer): - class Meta: - model = Post - fields = ('owner', 'title_post', 'description_post', 'created','updated','id') - - -class RevPostSerializer(serializers.ModelSerializer): - class Meta: - model = RevPost - fields = ('owner_rev_post', 'owner_rev', 'title_post_rev', 'description_post_rev', 'created','id','title_change','description_change','id') - -#Peacetrack begins here - -class RegionSerializer(serializers.ModelSerializer): - class Meta: - model = Region - fields = ('region_name','id') - - -class SectorSerializer(serializers.ModelSerializer): - class Meta: - model = Sector - fields = ('sector_name','sector_desc','sector_code','id') - -class PTPostSerializer(serializers.ModelSerializer): - class Meta: - model = PTPost - fields = ('post_name','post_region','sector','id') - -class ProjectSerializer(serializers.ModelSerializer): - class Meta: - model = Project - fields = ('project_name','project_purpose','project_sector') - -class GoalSerializer(serializers.ModelSerializer): - class Meta: - model = Goal - fields = ('goal_name','goal_title','goal_stmt','goal_project','id') - -class ObjectiveSerializer(serializers.ModelSerializer): - class Meta: - model = Objective - fields = ('obj_name','obj_title','obj_stmt','obj_goal','id') - -class IndicatorSerializer(serializers.ModelSerializer): - class Meta: - model = Indicator - fields = ('ind_obj','ind_type_1','ind_type_2','id') - -class OutputSerializer(serializers.ModelSerializer): - class Meta: - model = Output - fields = ('output_sector','output_ptpost','output_ind','output_value','id') - - -class OutcomeSerializer(serializers.ModelSerializer): - class Meta: - model = Outcome - fields = ('outcome_sector','outcome_ptpost','outcome_ind','outcome_value','id') - -class ActivitySerializer(serializers.ModelSerializer): - class Meta: - model = Activity - fields = ('activity_title','activity_desc','activity_cohort','activity_created','activity_output','id') - -class MeasurementSerializer(serializers.ModelSerializer): - class Meta: - model = Measurement - fields = ('meas_title','meas_desc','meas_cohort','meas_created','meas_outcome','id') - -class CohortSerializer(serializers.ModelSerializer): - class Meta: - model = Cohort - fields = ('cohort_name','cohort_desc','cohort_no_of_members','cohort_age','cohort_males','cohort_females','cohort_pos','cohort_notes','id') - -class VolunteerSerializer(serializers.ModelSerializer): - class Meta: - model = Volunteer - fields = ('vol_name','vol_sector','vol_ptpost','vol_activity','vol_meas','vol_cohort','id') diff --git a/webhub/setup.py b/webhub/setup.py deleted file mode 100644 index c563faf5..00000000 --- a/webhub/setup.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python - -from os import path -import sys -python_version = sys.version_info[:2] - -if python_version < (2, 6): - raise Exception("This version of xlrd requires Python 2.6 or above. " - "For older versions of Python, you can use the 0.8 series.") - -av = sys.argv -if len(av) > 1 and av[1].lower() == "--egg": - del av[1] - from setuptools import setup -else: - from distutils.core import setup - -from xlrd.info import __VERSION__ - -setup( - name = 'xlrd', - version = __VERSION__, - author = 'John Machin', - author_email = 'sjmachin@lexicon.net', - url = 'http://www.python-excel.org/', - packages = ['xlrd'], - scripts = [ - 'scripts/runxlrd.py', - ], - package_data={ - 'xlrd': [ - 'doc/*.htm*', - # 'doc/*.txt', - 'examples/*.*', - ], - - }, - description = 'Library for developers to extract data from Microsoft Excel (tm) spreadsheet files', - long_description = \ - "Extract data from Excel spreadsheets (.xls and .xlsx, versions 2.0 onwards) on any platform. " \ - "Pure Python (2.6, 2.7, 3.2+). Strong support for Excel dates. Unicode-aware.", - platforms = ["Any platform -- don't need Windows"], - license = 'BSD', - keywords = ['xls', 'excel', 'spreadsheet', 'workbook'], - classifiers = [ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 3', - 'Operating System :: OS Independent', - 'Topic :: Database', - 'Topic :: Office/Business', - 'Topic :: Software Development :: Libraries :: Python Modules', - ], - ) diff --git a/webhub/temp/tests/Formate.xls b/webhub/temp/tests/Formate.xls deleted file mode 100644 index 808cafb4..00000000 Binary files a/webhub/temp/tests/Formate.xls and /dev/null differ diff --git a/webhub/temp/tests/base.py b/webhub/temp/tests/base.py deleted file mode 100644 index d7a577a6..00000000 --- a/webhub/temp/tests/base.py +++ /dev/null @@ -1,4 +0,0 @@ -import os - -def from_this_dir(filename): - return os.path.join(os.path.dirname(os.path.abspath(__file__)), filename) diff --git a/webhub/temp/tests/formula_test_names.xls b/webhub/temp/tests/formula_test_names.xls deleted file mode 100644 index b6d98c7a..00000000 Binary files a/webhub/temp/tests/formula_test_names.xls and /dev/null differ diff --git a/webhub/temp/tests/formula_test_sjmachin.xls b/webhub/temp/tests/formula_test_sjmachin.xls deleted file mode 100644 index 82170088..00000000 Binary files a/webhub/temp/tests/formula_test_sjmachin.xls and /dev/null differ diff --git a/webhub/temp/tests/issue20.xls b/webhub/temp/tests/issue20.xls deleted file mode 100644 index d017343a..00000000 Binary files a/webhub/temp/tests/issue20.xls and /dev/null differ diff --git a/webhub/temp/tests/merged_cells.xlsx b/webhub/temp/tests/merged_cells.xlsx deleted file mode 100644 index 2d94fa29..00000000 Binary files a/webhub/temp/tests/merged_cells.xlsx and /dev/null differ diff --git a/webhub/temp/tests/picture_in_cell.xls b/webhub/temp/tests/picture_in_cell.xls deleted file mode 100644 index fa62e287..00000000 Binary files a/webhub/temp/tests/picture_in_cell.xls and /dev/null differ diff --git a/webhub/temp/tests/profiles.xls b/webhub/temp/tests/profiles.xls deleted file mode 100644 index 1254f02f..00000000 Binary files a/webhub/temp/tests/profiles.xls and /dev/null differ diff --git a/webhub/temp/tests/ragged.xls b/webhub/temp/tests/ragged.xls deleted file mode 100644 index 2bef15b4..00000000 Binary files a/webhub/temp/tests/ragged.xls and /dev/null differ diff --git a/webhub/temp/tests/reveng1.xlsx b/webhub/temp/tests/reveng1.xlsx deleted file mode 100644 index 099e26b2..00000000 Binary files a/webhub/temp/tests/reveng1.xlsx and /dev/null differ diff --git a/webhub/temp/tests/test_biffh.py b/webhub/temp/tests/test_biffh.py deleted file mode 100644 index 3a253ad3..00000000 --- a/webhub/temp/tests/test_biffh.py +++ /dev/null @@ -1,22 +0,0 @@ -import unittest -import sys - -if sys.version_info[0] >= 3: - from io import StringIO -else: - # Python 2.6+ does have the io module, but io.StringIO is strict about - # unicode, which won't work for our test. - from StringIO import StringIO - -from xlrd import biffh - -class TestHexDump(unittest.TestCase): - def test_hex_char_dump(self): - sio = StringIO() - biffh.hex_char_dump(b"abc\0e\01", 0, 6, fout=sio) - s = sio.getvalue() - assert "61 62 63 00 65 01" in s, s - assert "abc~e?" in s, s - -if __name__=='__main__': - unittest.main() diff --git a/webhub/temp/tests/test_cell.py b/webhub/temp/tests/test_cell.py deleted file mode 100644 index 3190ef76..00000000 --- a/webhub/temp/tests/test_cell.py +++ /dev/null @@ -1,64 +0,0 @@ -# Portions Copyright (C) 2010, Manfred Moitzi under a BSD licence - -import sys -import os -import unittest - -import xlrd - -from .base import from_this_dir - -class TestCell(unittest.TestCase): - - def setUp(self): - self.book = xlrd.open_workbook(from_this_dir('profiles.xls'), formatting_info=True) - self.sheet = self.book.sheet_by_name('PROFILEDEF') - - def test_string_cell(self): - cell = self.sheet.cell(0, 0) - self.assertEqual(cell.ctype, xlrd.book.XL_CELL_TEXT) - self.assertEqual(cell.value, 'PROFIL') - self.assertTrue(cell.xf_index > 0) - - def test_number_cell(self): - cell = self.sheet.cell(1, 1) - self.assertEqual(cell.ctype, xlrd.book.XL_CELL_NUMBER) - self.assertEqual(cell.value, 100) - self.assertTrue(cell.xf_index > 0) - - def test_calculated_cell(self): - sheet2 = self.book.sheet_by_name('PROFILELEVELS') - cell = sheet2.cell(1, 3) - self.assertEqual(cell.ctype, xlrd.book.XL_CELL_NUMBER) - self.assertAlmostEqual(cell.value, 265.131, places=3) - self.assertTrue(cell.xf_index > 0) - - def test_merged_cells(self): - book = xlrd.open_workbook(from_this_dir('xf_class.xls'), formatting_info=True) - sheet3 = book.sheet_by_name('table2') - row_lo, row_hi, col_lo, col_hi = sheet3.merged_cells[0] - self.assertEqual(sheet3.cell(row_lo, col_lo).value, 'MERGED') - self.assertEqual((row_lo, row_hi, col_lo, col_hi), (3, 7, 2, 5)) - - def test_merged_cells_xlsx(self): - book = xlrd.open_workbook(from_this_dir('merged_cells.xlsx')) - - sheet1 = book.sheet_by_name('Sheet1') - expected = [] - got = sheet1.merged_cells - self.assertEqual(expected, got) - - sheet2 = book.sheet_by_name('Sheet2') - expected = [(0, 1, 0, 2)] - got = sheet2.merged_cells - self.assertEqual(expected, got) - - sheet3 = book.sheet_by_name('Sheet3') - expected = [(0, 1, 0, 2), (0, 1, 2, 4), (1, 4, 0, 2), (1, 9, 2, 4)] - got = sheet3.merged_cells - self.assertEqual(expected, got) - - sheet4 = book.sheet_by_name('Sheet4') - expected = [(0, 1, 0, 2), (2, 20, 0, 1), (1, 6, 2, 5)] - got = sheet4.merged_cells - self.assertEqual(expected, got) diff --git a/webhub/temp/tests/test_comments_excel.xlsx b/webhub/temp/tests/test_comments_excel.xlsx deleted file mode 100644 index cdc2465d..00000000 Binary files a/webhub/temp/tests/test_comments_excel.xlsx and /dev/null differ diff --git a/webhub/temp/tests/test_comments_gdocs.xlsx b/webhub/temp/tests/test_comments_gdocs.xlsx deleted file mode 100644 index 2f8e5e1b..00000000 Binary files a/webhub/temp/tests/test_comments_gdocs.xlsx and /dev/null differ diff --git a/webhub/temp/tests/test_formats.py b/webhub/temp/tests/test_formats.py deleted file mode 100644 index 559ad134..00000000 --- a/webhub/temp/tests/test_formats.py +++ /dev/null @@ -1,77 +0,0 @@ - # -*- coding: utf-8 -*- - # Portions Copyright (C) 2010, Manfred Moitzi under a BSD licence - -from unittest import TestCase -import sys -import os - -import xlrd - -if sys.version_info[0] >= 3: - def u(s): return s -else: - def u(s): - return s.decode('utf-8') - -from .base import from_this_dir - -class TestCellContent(TestCase): - - def setUp(self): - self.book = xlrd.open_workbook(from_this_dir('Formate.xls'), formatting_info=True) - self.sheet = self.book.sheet_by_name(u('Blätt1')) - - def test_text_cells(self): - for row, name in enumerate([u('Huber'), u('Äcker'), u('Öcker')]): - cell = self.sheet.cell(row, 0) - self.assertEqual(cell.ctype, xlrd.book.XL_CELL_TEXT) - self.assertEqual(cell.value, name) - self.assertTrue(cell.xf_index > 0) - - def test_date_cells(self): - # see also 'Dates in Excel spreadsheets' in the documentation - # convert: xldate_as_tuple(float, book.datemode) -> (year, month, - # day, hour, minutes, seconds) - for row, date in [(0, 2741.), (1, 38406.), (2, 32266.)]: - cell = self.sheet.cell(row, 1) - self.assertEqual(cell.ctype, xlrd.book.XL_CELL_DATE) - self.assertEqual(cell.value, date) - self.assertTrue(cell.xf_index > 0) - - def test_time_cells(self): - # see also 'Dates in Excel spreadsheets' in the documentation - # convert: xldate_as_tuple(float, book.datemode) -> (year, month, - # day, hour, minutes, seconds) - for row, time in [(3, .273611), (4, .538889), (5, .741123)]: - cell = self.sheet.cell(row, 1) - self.assertEqual(cell.ctype, xlrd.book.XL_CELL_DATE) - self.assertAlmostEqual(cell.value, time, places=6) - self.assertTrue(cell.xf_index > 0) - - def test_percent_cells(self): - for row, time in [(6, .974), (7, .124)]: - cell = self.sheet.cell(row, 1) - self.assertEqual(cell.ctype, xlrd.book.XL_CELL_NUMBER) - self.assertAlmostEqual(cell.value, time, places=3) - self.assertTrue(cell.xf_index > 0) - - def test_currency_cells(self): - for row, time in [(8, 1000.30), (9, 1.20)]: - cell = self.sheet.cell(row, 1) - self.assertEqual(cell.ctype, xlrd.book.XL_CELL_NUMBER) - self.assertAlmostEqual(cell.value, time, places=2) - self.assertTrue(cell.xf_index > 0) - - def test_get_from_merged_cell(self): - sheet = self.book.sheet_by_name(u('ÖÄÜ')) - cell = sheet.cell(2, 2) - self.assertEqual(cell.ctype, xlrd.book.XL_CELL_TEXT) - self.assertEqual(cell.value, 'MERGED CELLS') - self.assertTrue(cell.xf_index > 0) - - def test_ignore_diagram(self): - sheet = self.book.sheet_by_name(u('Blätt3')) - cell = sheet.cell(0, 0) - self.assertEqual(cell.ctype, xlrd.book.XL_CELL_NUMBER) - self.assertEqual(cell.value, 100) - self.assertTrue(cell.xf_index > 0) diff --git a/webhub/temp/tests/test_formulas.py b/webhub/temp/tests/test_formulas.py deleted file mode 100644 index acf6d245..00000000 --- a/webhub/temp/tests/test_formulas.py +++ /dev/null @@ -1,83 +0,0 @@ - # -*- coding: utf-8 -*- -# Portions Copyright (C) 2010, Manfred Moitzi under a BSD licence - -from unittest import TestCase -import os -import sys - -import xlrd - -from .base import from_this_dir - -try: - ascii -except NameError: - # For Python 2 - def ascii(s): - a = repr(s) - if a.startswith(('u"', "u'")): - a = a[1:] - return a - -class TestFormulas(TestCase): - - def setUp(self): - book = xlrd.open_workbook(from_this_dir('formula_test_sjmachin.xls')) - self.sheet = book.sheet_by_index(0) - - def get_value(self, col, row): - return ascii(self.sheet.col_values(col)[row]) - - def test_cell_B2(self): - self.assertEqual( - self.get_value(1, 1), - r"'\u041c\u041e\u0421\u041a\u0412\u0410 \u041c\u043e\u0441\u043a\u0432\u0430'" - ) - - def test_cell_B3(self): - self.assertEqual(self.get_value(1, 2), '0.14285714285714285') - - def test_cell_B4(self): - self.assertEqual(self.get_value(1, 3), "'ABCDEF'") - - def test_cell_B5(self): - self.assertEqual(self.get_value(1, 4), "''") - - def test_cell_B6(self): - self.assertEqual(self.get_value(1, 5), '1') - - def test_cell_B7(self): - self.assertEqual(self.get_value(1, 6), '7') - - def test_cell_B8(self): - self.assertEqual( - self.get_value(1, 7), - r"'\u041c\u041e\u0421\u041a\u0412\u0410 \u041c\u043e\u0441\u043a\u0432\u0430'" - ) - -class TestNameFormulas(TestCase): - - def setUp(self): - book = xlrd.open_workbook(from_this_dir('formula_test_names.xls')) - self.sheet = book.sheet_by_index(0) - - def get_value(self, col, row): - return ascii(self.sheet.col_values(col)[row]) - - def test_unaryop(self): - self.assertEqual(self.get_value(1, 1), '-7.0') - - def test_attrsum(self): - self.assertEqual(self.get_value(1, 2), '4.0') - - def test_func(self): - self.assertEqual(self.get_value(1, 3), '6.0') - - def test_func_var_args(self): - self.assertEqual(self.get_value(1, 4), '3.0') - - def test_if(self): - self.assertEqual(self.get_value(1, 5), "'b'") - - def test_choose(self): - self.assertEqual(self.get_value(1, 6), "'C'") diff --git a/webhub/temp/tests/test_open_workbook.py b/webhub/temp/tests/test_open_workbook.py deleted file mode 100644 index 70edd951..00000000 --- a/webhub/temp/tests/test_open_workbook.py +++ /dev/null @@ -1,38 +0,0 @@ -from unittest import TestCase - -import os - -from xlrd import open_workbook - -from .base import from_this_dir - -class TestOpen(TestCase): - # test different uses of open_workbook - - def test_names_demo(self): - # For now, we just check this doesn't raise an error. - open_workbook( - from_this_dir(os.path.join('..','xlrd','examples','namesdemo.xls')) - ) - - def test_ragged_rows_tidied_with_formatting(self): - # For now, we just check this doesn't raise an error. - open_workbook(from_this_dir('issue20.xls'), - formatting_info=True) - - def test_BYTES_X00(self): - # For now, we just check this doesn't raise an error. - open_workbook(from_this_dir('picture_in_cell.xls'), - formatting_info=True) - - def test_xlsx_simple(self): - # For now, we just check this doesn't raise an error. - open_workbook(from_this_dir('text_bar.xlsx')) - # we should make assertions here that data has been - # correctly processed. - - def test_xlsx(self): - # For now, we just check this doesn't raise an error. - open_workbook(from_this_dir('reveng1.xlsx')) - # we should make assertions here that data has been - # correctly processed. diff --git a/webhub/temp/tests/test_sheet.py b/webhub/temp/tests/test_sheet.py deleted file mode 100644 index e1da4a99..00000000 --- a/webhub/temp/tests/test_sheet.py +++ /dev/null @@ -1,128 +0,0 @@ -# Portions Copyright (C) 2010, Manfred Moitzi under a BSD licence - -from unittest import TestCase - -import sys -import os -import unittest - -import xlrd - -from .base import from_this_dir - -SHEETINDEX = 0 -NROWS = 15 -NCOLS = 13 - -ROW_ERR = NROWS + 10 -COL_ERR = NCOLS + 10 - -class TestSheet(TestCase): - - sheetnames = ['PROFILEDEF', 'AXISDEF', 'TRAVERSALCHAINAGE', - 'AXISDATUMLEVELS', 'PROFILELEVELS'] - - def setUp(self): - self.book = xlrd.open_workbook(from_this_dir('profiles.xls'), formatting_info=True) - - def check_sheet_function(self, function): - self.assertTrue(function(0, 0)) - self.assertTrue(function(NROWS-1, NCOLS-1)) - - def check_sheet_function_index_error(self, function): - self.assertRaises(IndexError, function, ROW_ERR, 0) - self.assertRaises(IndexError, function, 0, COL_ERR) - - def check_col_slice(self, col_function): - _slice = col_function(0, 2, NROWS-2) - self.assertEqual(len(_slice), NROWS-4) - - def check_row_slice(self, row_function): - _slice = row_function(0, 2, NCOLS-2) - self.assertEqual(len(_slice), NCOLS-4) - - def test_nrows(self): - sheet = self.book.sheet_by_index(SHEETINDEX) - self.assertEqual(sheet.nrows, NROWS) - - def test_ncols(self): - sheet = self.book.sheet_by_index(SHEETINDEX) - self.assertEqual(sheet.ncols, NCOLS) - - def test_cell(self): - sheet = self.book.sheet_by_index(SHEETINDEX) - self.assertNotEqual(xlrd.empty_cell, sheet.cell(0, 0)) - self.assertNotEqual(xlrd.empty_cell, sheet.cell(NROWS-1, NCOLS-1)) - - def test_cell_error(self): - sheet = self.book.sheet_by_index(SHEETINDEX) - self.check_sheet_function_index_error(sheet.cell) - - def test_cell_type(self): - sheet = self.book.sheet_by_index(SHEETINDEX) - self.check_sheet_function(sheet.cell_type) - - def test_cell_type_error(self): - sheet = self.book.sheet_by_index(SHEETINDEX) - self.check_sheet_function_index_error(sheet.cell_type) - - def test_cell_value(self): - sheet = self.book.sheet_by_index(SHEETINDEX) - self.check_sheet_function(sheet.cell_value) - - def test_cell_value_error(self): - sheet = self.book.sheet_by_index(SHEETINDEX) - self.check_sheet_function_index_error(sheet.cell_value) - - def test_cell_xf_index(self): - sheet = self.book.sheet_by_index(SHEETINDEX) - self.check_sheet_function(sheet.cell_xf_index) - - def test_cell_xf_index_error(self): - sheet = self.book.sheet_by_index(SHEETINDEX) - self.check_sheet_function_index_error(sheet.cell_xf_index) - - def test_col(self): - sheet = self.book.sheet_by_index(SHEETINDEX) - col = sheet.col(0) - self.assertEqual(len(col), NROWS) - - def test_row(self): - sheet = self.book.sheet_by_index(SHEETINDEX) - row = sheet.row(0) - self.assertEqual(len(row), NCOLS) - - def test_col_slice(self): - sheet = self.book.sheet_by_index(SHEETINDEX) - self.check_col_slice(sheet.col_slice) - - def test_col_types(self): - sheet = self.book.sheet_by_index(SHEETINDEX) - self.check_col_slice(sheet.col_types) - - def test_col_values(self): - sheet = self.book.sheet_by_index(SHEETINDEX) - self.check_col_slice(sheet.col_values) - - def test_row_slice(self): - sheet = self.book.sheet_by_index(SHEETINDEX) - self.check_row_slice(sheet.row_slice) - - def test_row_types(self): - sheet = self.book.sheet_by_index(SHEETINDEX) - self.check_row_slice(sheet.col_types) - - def test_row_values(self): - sheet = self.book.sheet_by_index(SHEETINDEX) - self.check_col_slice(sheet.row_values) - -class TestSheetRagged(TestCase): - - def test_read_ragged(self): - book = xlrd.open_workbook(from_this_dir('ragged.xls'), ragged_rows=True) - sheet = book.sheet_by_index(0) - self.assertEqual(sheet.row_len(0), 3) - self.assertEqual(sheet.row_len(1), 2) - self.assertEqual(sheet.row_len(2), 1) - self.assertEqual(sheet.row_len(3), 4) - self.assertEqual(sheet.row_len(4), 4) diff --git a/webhub/temp/tests/test_workbook.py b/webhub/temp/tests/test_workbook.py deleted file mode 100644 index b9caddf3..00000000 --- a/webhub/temp/tests/test_workbook.py +++ /dev/null @@ -1,47 +0,0 @@ -# Portions Copyright (C) 2010, Manfred Moitzi under a BSD licence - -from unittest import TestCase -import os -import sys - -from xlrd import open_workbook -from xlrd.book import Book -from xlrd.sheet import Sheet - -from .base import from_this_dir - -class TestWorkbook(TestCase): - - sheetnames = ['PROFILEDEF', 'AXISDEF', 'TRAVERSALCHAINAGE', - 'AXISDATUMLEVELS', 'PROFILELEVELS'] - - def setUp(self): - self.book = open_workbook(from_this_dir('profiles.xls')) - - def test_open_workbook(self): - self.assertTrue(isinstance(self.book, Book)) - - def test_nsheets(self): - self.assertEqual(self.book.nsheets, 5) - - def test_sheet_by_name(self): - for name in self.sheetnames: - sheet = self.book.sheet_by_name(name) - self.assertTrue(isinstance(sheet, Sheet)) - self.assertEqual(name, sheet.name) - - def test_sheet_by_index(self): - for index in range(5): - sheet = self.book.sheet_by_index(index) - self.assertTrue(isinstance(sheet, Sheet)) - self.assertEqual(sheet.name, self.sheetnames[index]) - - def test_sheets(self): - sheets = self.book.sheets() - for index, sheet in enumerate(sheets): - self.assertTrue(isinstance(sheet, Sheet)) - self.assertEqual(sheet.name, self.sheetnames[index]) - - def test_sheet_names(self): - self.assertEqual(self.sheetnames, self.book.sheet_names()) - diff --git a/webhub/temp/tests/test_xldate.py b/webhub/temp/tests/test_xldate.py deleted file mode 100644 index 0a3a1a5c..00000000 --- a/webhub/temp/tests/test_xldate.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python -# Author: mozman -# Purpose: test xldate.py -# Created: 04.12.2010 -# Copyright (C) 2010, Manfred Moitzi -# License: BSD licence - -import sys -import unittest - -from xlrd import xldate - -DATEMODE = 0 # 1900-based - -class TestXLDate(unittest.TestCase): - def test_date_as_tuple(self): - date = xldate.xldate_as_tuple(2741., DATEMODE) - self.assertEqual(date, (1907, 7, 3, 0, 0, 0)) - date = xldate.xldate_as_tuple(38406., DATEMODE) - self.assertEqual(date, (2005, 2, 23, 0, 0, 0)) - date = xldate.xldate_as_tuple(32266., DATEMODE) - self.assertEqual(date, (1988, 5, 3, 0, 0, 0)) - - def test_time_as_tuple(self): - time = xldate.xldate_as_tuple(.273611, DATEMODE) - self.assertEqual(time, (0, 0, 0, 6, 34, 0)) - time = xldate.xldate_as_tuple(.538889, DATEMODE) - self.assertEqual(time, (0, 0, 0, 12, 56, 0)) - time = xldate.xldate_as_tuple(.741123, DATEMODE) - self.assertEqual(time, (0, 0, 0, 17, 47, 13)) - - def test_xldate_from_date_tuple(self): - date = xldate.xldate_from_date_tuple( (1907, 7, 3), DATEMODE ) - self.assertAlmostEqual(date, 2741.) - date = xldate.xldate_from_date_tuple( (2005, 2, 23), DATEMODE ) - self.assertAlmostEqual(date, 38406.) - date = xldate.xldate_from_date_tuple( (1988, 5, 3), DATEMODE ) - self.assertAlmostEqual(date, 32266.) - - def test_xldate_from_time_tuple(self): - time = xldate.xldate_from_time_tuple( (6, 34, 0) ) - self.assertAlmostEqual(time, .273611, places=6) - time = xldate.xldate_from_time_tuple( (12, 56, 0) ) - self.assertAlmostEqual(time, .538889, places=6) - time = xldate.xldate_from_time_tuple( (17, 47, 13) ) - self.assertAlmostEqual(time, .741123, places=6) - - def test_xldate_from_datetime_tuple(self): - date = xldate.xldate_from_datetime_tuple( (1907, 7, 3, 6, 34, 0), DATEMODE) - self.assertAlmostEqual(date, 2741.273611, places=6) - date = xldate.xldate_from_datetime_tuple( (2005, 2, 23, 12, 56, 0), DATEMODE) - self.assertAlmostEqual(date, 38406.538889, places=6) - date = xldate.xldate_from_datetime_tuple( (1988, 5, 3, 17, 47, 13), DATEMODE) - self.assertAlmostEqual(date, 32266.741123, places=6) - -if __name__=='__main__': - unittest.main() diff --git a/webhub/temp/tests/test_xldate_to_datetime.py b/webhub/temp/tests/test_xldate_to_datetime.py deleted file mode 100644 index 302997f7..00000000 --- a/webhub/temp/tests/test_xldate_to_datetime.py +++ /dev/null @@ -1,164 +0,0 @@ -############################################################################### -# -# Tests for the xlrd xldate.xldate_as_datetime() function. -# - -import unittest -from datetime import datetime -from xlrd import xldate - -not_1904 = False -is_1904 = True - - -class TestConvertToDateTime(unittest.TestCase): - """ - Testcases to test the _xldate_to_datetime() function against dates - extracted from Excel files, with 1900/1904 epochs. - - """ - - def test_dates_and_times_1900_epoch(self): - """ - Test the _xldate_to_datetime() function for dates and times in - the Excel standard 1900 epoch. - - """ - # Test Excel dates strings and corresponding serial date numbers taken - # from an Excel file. - excel_dates = [ - # Excel's 0.0 date in the 1900 epoch is 1 day before 1900. - ('1899-12-31T00:00:00.000', 0), - - # Date/time before the false Excel 1900 leapday. - ('1900-02-28T02:11:11.986', 59.09111094906), - - # Date/time after the false Excel 1900 leapday. - ('1900-03-01T05:46:44.068', 61.24078782403), - - # Random date/times in Excel's 0-9999.9999+ range. - ('1982-08-25T00:15:20.213', 30188.010650613425), - ('2065-04-19T00:16:48.290', 60376.011670023145), - ('3222-06-11T03:08:08.251', 483014.13065105322), - ('4379-08-03T06:14:48.580', 905652.26028449077), - ('5949-12-30T12:59:54.263', 1479232.5416002662), - - # End of Excel's date range. - ('9999-12-31T23:59:59.000', 2958465.999988426), - ] - - # Convert the Excel date strings to datetime objects and compare - # against the dateitme return value of xldate.xldate_as_datetime(). - for excel_date in excel_dates: - exp = datetime.strptime(excel_date[0], "%Y-%m-%dT%H:%M:%S.%f") - got = xldate.xldate_as_datetime(excel_date[1], not_1904) - - self.assertEqual(got, exp) - - def test_dates_only_1900_epoch(self): - """ - Test the _xldate_to_datetime() function for dates in the Excel - standard 1900 epoch. - - """ - # Test Excel dates strings and corresponding serial date numbers taken - # from an Excel file. - excel_dates = [ - # Excel's day 0 in the 1900 epoch is 1 day before 1900. - ('1899-12-31', 0), - - # Excel's day 1 in the 1900 epoch. - ('1900-01-01', 1), - - # Date/time before the false Excel 1900 leapday. - ('1900-02-28', 59), - - # Date/time after the false Excel 1900 leapday. - ('1900-03-01', 61), - - # Random date/times in Excel's 0-9999.9999+ range. - ('1902-09-27', 1001), - ('1999-12-31', 36525), - ('2000-01-01', 36526), - ('4000-12-31', 767376), - ('4321-01-01', 884254), - ('9999-01-01', 2958101), - - # End of Excel's date range. - ('9999-12-31', 2958465), - ] - - # Convert the Excel date strings to datetime objects and compare - # against the dateitme return value of xldate.xldate_as_datetime(). - for excel_date in excel_dates: - exp = datetime.strptime(excel_date[0], "%Y-%m-%d") - got = xldate.xldate_as_datetime(excel_date[1], not_1904) - - self.assertEqual(got, exp) - - def test_dates_only_1904_epoch(self): - """ - Test the _xldate_to_datetime() function for dates in the Excel - Mac/1904 epoch. - - """ - # Test Excel dates strings and corresponding serial date numbers taken - # from an Excel file. - excel_dates = [ - # Excel's day 0 in the 1904 epoch. - ('1904-01-01', 0), - - # Random date/times in Excel's 0-9999.9999+ range. - ('1904-01-31', 30), - ('1904-08-31', 243), - ('1999-02-28', 34757), - ('1999-12-31', 35063), - ('2000-01-01', 35064), - ('2400-12-31', 181526), - ('4000-01-01', 765549), - ('9999-01-01', 2956639), - - # End of Excel's date range. - ('9999-12-31', 2957003), - ] - - # Convert the Excel date strings to datetime objects and compare - # against the dateitme return value of xldate.xldate_as_datetime(). - for excel_date in excel_dates: - exp = datetime.strptime(excel_date[0], "%Y-%m-%d") - got = xldate.xldate_as_datetime(excel_date[1], is_1904) - - self.assertEqual(got, exp) - - def test_times_only(self): - """ - Test the _xldate_to_datetime() function for times only, i.e, the - fractional part of the Excel date when the serial date is 0. - - """ - # Test Excel dates strings and corresponding serial date numbers taken - # from an Excel file. The 1899-12-31 date is Excel's day 0. - excel_dates = [ - # Random times in Excel's 0-0.9999+ range for 1 day. - ('1899-12-31T00:00:00.000', 0), - ('1899-12-31T00:15:20.213', 1.0650613425925924E-2), - ('1899-12-31T02:24:37.095', 0.10042934027777778), - ('1899-12-31T04:56:35.792', 0.2059698148148148), - ('1899-12-31T07:31:20.407', 0.31343063657407405), - ('1899-12-31T09:37:23.945', 0.40097158564814817), - ('1899-12-31T12:09:48.602', 0.50681252314814818), - ('1899-12-31T14:37:57.451', 0.60969271990740748), - ('1899-12-31T17:04:02.415', 0.71113906250000003), - ('1899-12-31T19:14:24.673', 0.80167445601851861), - ('1899-12-31T21:39:05.944', 0.90215212962962965), - ('1899-12-31T23:17:12.632', 0.97028509259259266), - ('1899-12-31T23:59:59.999', 0.99999998842592586), - ] - - # Convert the Excel date strings to datetime objects and compare - # against the dateitme return value of xldate.xldate_as_datetime(). - for excel_date in excel_dates: - exp = datetime.strptime(excel_date[0], "%Y-%m-%dT%H:%M:%S.%f") - got = xldate.xldate_as_datetime(excel_date[1], not_1904) - - self.assertEqual(got, exp) diff --git a/webhub/temp/tests/test_xlsx_comments.py b/webhub/temp/tests/test_xlsx_comments.py deleted file mode 100644 index 456ffc18..00000000 --- a/webhub/temp/tests/test_xlsx_comments.py +++ /dev/null @@ -1,46 +0,0 @@ -from unittest import TestCase - -import os - -from xlrd import open_workbook - -from .base import from_this_dir - -class TestXlsxComments(TestCase): - - def test_excel_comments(self): - book = open_workbook(from_this_dir('test_comments_excel.xlsx')) - sheet = book.sheet_by_index(0) - - note_map = sheet.cell_note_map - self.assertEqual(len(note_map), 1) - self.assertEqual(note_map[(0, 1)].text, 'hello') - - def test_excel_comments_multiline(self): - book = open_workbook(from_this_dir('test_comments_excel.xlsx')) - sheet = book.sheet_by_index(1) - - note_map = sheet.cell_note_map - self.assertEqual(note_map[(1, 2)].text, '1st line\n2nd line') - - def test_excel_comments_two_t_elements(self): - book = open_workbook(from_this_dir('test_comments_excel.xlsx')) - sheet = book.sheet_by_index(2) - - note_map = sheet.cell_note_map - self.assertEqual(note_map[(0, 0)].text, 'Author:\nTwo t elements') - - def test_excel_comments_no_t_elements(self): - book = open_workbook(from_this_dir('test_comments_excel.xlsx')) - sheet = book.sheet_by_index(3) - - note_map = sheet.cell_note_map - self.assertEqual(note_map[(0,0)].text, '') - - def test_gdocs_comments(self): - book = open_workbook(from_this_dir('test_comments_gdocs.xlsx')) - sheet = book.sheet_by_index(0) - - note_map = sheet.cell_note_map - self.assertEqual(len(note_map), 1) - self.assertEqual(note_map[(0, 1)].text, 'Just a test') diff --git a/webhub/temp/tests/text_bar.xlsx b/webhub/temp/tests/text_bar.xlsx deleted file mode 100644 index 9e30e636..00000000 Binary files a/webhub/temp/tests/text_bar.xlsx and /dev/null differ diff --git a/webhub/temp/tests/xf_class.xls b/webhub/temp/tests/xf_class.xls deleted file mode 100644 index 41db86cc..00000000 Binary files a/webhub/temp/tests/xf_class.xls and /dev/null differ diff --git a/webhub/urls.py b/webhub/urls.py index 2e528828..b2918ec5 100644 --- a/webhub/urls.py +++ b/webhub/urls.py @@ -1,85 +1,44 @@ -from django.conf.urls import patterns, url, include +from django.conf.urls import include, url from rest_framework import routers -from malaria import views as malaria_views -from peacetrack import views as peacetrack_views + +from malaria_api import views as malaria_api_views +from pcsa import views as pcsa_views +from pcsa_GHN import views as ghn_views +from pcsa_safety_tools import views as safetytools_views +from profiles import views as profiles_views from webhub import views +from firstaide import views as firstaide_views +from django.views.generic import RedirectView +from webhub.views import DashboardView, ListUsers, PcuserDetail, AboutPC, Policies, Details, HelpPC, PostSearchView, LoginReal +from profiles.views import ProfileView, EditProfile + + router = routers.DefaultRouter() router.register(r'users', views.UserViewSet) -router.register(r'posts', malaria_views.PostViewSet) -router.register(r'revposts', malaria_views.RevPostViewSet) -router.register(r'regions', peacetrack_views.RegionViewSet) -router.register(r'sectors', peacetrack_views.SectorViewSet) -router.register(r'ptposts', peacetrack_views.PTPostViewSet) -router.register(r'projects', peacetrack_views.ProjectViewSet) -router.register(r'goals', peacetrack_views.GoalViewSet) -router.register(r'objectives', peacetrack_views.ObjectiveViewSet) -router.register(r'indicators', peacetrack_views.IndicatorViewSet) -router.register(r'outputs', peacetrack_views.OutputViewSet) -router.register(r'outcomes', peacetrack_views.OutcomeViewSet) -router.register(r'activity', peacetrack_views.ActivityViewSet) -router.register(r'measurement', peacetrack_views.MeasurementViewSet) -router.register(r'cohort', peacetrack_views.CohortViewSet) -router.register(r'volunteer', peacetrack_views.VolunteerViewSet) +router.register(r'pcsa_posts', pcsa_views.PcsaPostViewSet) +router.register(r'malaria_posts', malaria_api_views.PostViewSet) +router.register(r'malaria_users', malaria_api_views.MalariaUsersViewSet) +router.register(r'gethelpnow/posts', ghn_views.ghnPostsViewSet) +router.register(r'gethelpnow/contacts', ghn_views.ContactViewSet) +router.register(r'safetytools/posts', safetytools_views.SafetyToolsPostViewSet) +router.register(r'firstaide/(?P.+)', firstaide_views.FirstAideAPIViewSet,'base_name_argument') -urlpatterns = patterns( - '', - url(r'^index/$', - views.index, - name='index'), +urlpatterns = [ url(r'^$', - views.dashboard, + DashboardView.as_view(), name='dashboard'), - url(r'^signup_page/$', - views.signup_page, - name='signup_page'), - url(r'^signup_do/$', - views.signup_do, - name='signup_do'), - url(r'^send_verification_email/$', - views.send_verification_email, - name='send_verification_email'), - url(r'^send_email/$', - views.send_email, - name='send_email'), - url(r'^login_do/$', - views.login_do, - name='login_do'), - url(r'^logout_do/$', - views.logout_do, - name='logout_do'), url(r'^profile/$', - views.profile, + ProfileView.as_view(), name='profile'), - url(r'^edit_profile/$', - views.edit_profile, + url(r'^edit_profile/(?P\d+)/$', + EditProfile.as_view(), name='edit_profile'), - url(r'^edit_profile_page/$', - views.edit_profile_page, - name='edit_profile_page'), - url(r'^forgot_pass_page/$', - views.forgot_pass_page, - name='forgot_pass_page'), - url(r'^forgot_pass/$', - views.forgot_pass, - name='forgot_pass'), - url(r'^verify/$', - views.verify, - name='verify'), - url(r'^reset_pass_page/$', - views.reset_pass_page, - name='reset_pass_page'), - url(r'^change_pass/$', - views.change_pass, - name='change_pass'), - url(r'^change_pass_page/$', - views.change_pass_page, - name='change_pass_page'), url(r'^pcuser/$', - views.pcuser_list, + ListUsers.as_view(), name='pcuser_list'), url(r'^pcuser/(?P[0-9]+)/$', - views.pcuser_detail, + PcuserDetail.as_view(), name='pcuser_detail'), url(r'^api-auth/', include('rest_framework.urls', @@ -87,18 +46,20 @@ url(r'^api/', include(router.urls)), url(r'^aboutPC/$', - views.aboutPC, + AboutPC.as_view(), name='aboutPC'), url(r'^policies/$', - views.policies, + Policies.as_view(), name='policies'), url(r'^details/$', - views.details, + Details.as_view(), name='details'), url(r'^helpPC/$', - views.helpPC, + HelpPC.as_view(), name='helpPC'), - url(r'^testDB/$', - views.testDB, - name='testDB'), -) + url(r'^search/$', + PostSearchView.as_view(), + name='search'), + url(r'^login_real/$', LoginReal.as_view(), name = 'login_real'), + url(r'^login_social/$', views.login_social, name = 'login_social'), +] diff --git a/webhub/views.py b/webhub/views.py index 66403397..23e5b3d0 100644 --- a/webhub/views.py +++ b/webhub/views.py @@ -1,30 +1,33 @@ -import jinja2 -import smtplib -import uuid -from django.http import HttpResponse -from django.contrib.auth import authenticate, login, logout -from django.views.decorators.csrf import csrf_exempt + +from rest_framework.response import Response from django.contrib.auth.models import User -from jinja2.ext import loopcontrols -from rest_framework import viewsets -from rest_framework import status +from rest_framework import status, viewsets + from rest_framework.decorators import api_view -from rest_framework.response import Response -from webhub import xlrd -from webhub.checker import check -from webhub.models import * + +from django.shortcuts import render, redirect + from webhub.serializers import * +from django.views.generic import TemplateView, ListView +from django.contrib.auth.mixins import LoginRequiredMixin +from rest_framework.views import APIView +from profiles.models import Pcuser +from django.http import Http404 +from django.http import HttpResponse, HttpResponseRedirect +from webhub import views as webhub_view +from malaria_web.models import Post +from pcsa_GHN.models import ghnPost +from pcsa_safety_tools.models import SafetyToolsPost +from itertools import chain # SMTP port for sending emails SMTP_PORT = 465 -#link for the localhost +# Link for the localhost website = "http://systerspcweb.herokuapp.com/" -jinja_environ = jinja2.Environment(loader=jinja2.FileSystemLoader(['ui']), extensions=[loopcontrols]) - -#apis for malaria begin here +# APIs for malaria begin here class UserViewSet(viewsets.ModelViewSet): """ API endpoint that allows users to be viewed or edited. @@ -32,438 +35,180 @@ class UserViewSet(viewsets.ModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer - -#List all pcusers, or create a new pcuser. -@api_view(['GET', 'POST']) -def pcuser_list(request): - if request.method == 'GET': + +class ListUsers(APIView): + + def get(self, request, format=None): pcuser = Pcuser.objects.all() serializer = PcuserSerializer(pcuser, many=True) return Response(serializer.data) - elif request.method == 'POST': + def post(self, request, format=None): serializer = PcuserSerializer(data=request.DATA) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -#Retrieve, update or delete a pcuser instance. -@api_view(['GET', 'PUT', 'DELETE']) -def pcuser_detail(request, pk): - try: - pcuser = Pcuser.objects.get(pk=pk) - except Pcuser.DoesNotExist: - return Response(status=status.HTTP_404_NOT_FOUND) - if request.method == 'GET': - serializer = PcuserSerializer(pcuser) +class PcuserDetail(APIView): + + def get_object(self, pk): + try: + return Pcuser.objects.get(pk=pk) + except Pcuser.DoesNotExist: + raise Http404 + + def get(self, request, pk, format=None): + snippet = self.get_object(pk) + serializer = PcuserSerializer(snippet) return Response(serializer.data) - elif request.method == 'PUT': - serializer = PcuserSerializer(pcuser, data=request.DATA) + def put(self, request, pk, format=None): + snippet = self.get_object(pk) + serializer = PcuserSerializer(snippet, data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - elif request.method == 'DELETE': - pcuser.delete() + def delete(self, request, pk, format=None): + snippet = self.get_object(pk) + snippet.delete() return Response(status=status.HTTP_204_NO_CONTENT) - -#Calls index page -def index(request): - return HttpResponse(jinja_environ.get_template('index.html').render({"pcuser":None})) - -#Calls dashboard wish is shown after a user is logged in -def dashboard(request): - - retval = check(request) - if retval <> None: - return retval - - template_values = {'pcuser' : request.user.pcuser, - } - return HttpResponse(jinja_environ.get_template('dashboard.html').render(template_values)) -#Calls the signup page. If the user us already logged in, s/he will be redirected to dashboard. -def signup_page(request): - if request.user.is_authenticated(): - redirect_url = "/" - if 'redirect_url' in request.REQUEST.keys(): - redirect_url = request.REQUEST['redirect_url'] - return HttpResponse(jinja_environ.get_template('redirect.html').render({"pcuser":None,"redirect_url":redirect_url})) +# Display the main page of the project with malaria and pcsa app options +class DashboardView(LoginRequiredMixin,TemplateView): - else: - return HttpResponse(jinja_environ.get_template('signup.html').render({"pcuser":None})) - - -#Called when a user clicks submit button in signup. Here a verification mail is also sent to the user. -@csrf_exempt -def signup_do(request): - if request.user.is_authenticated(): - logout(request) - redirect_url = "/" - if 'redirect_url' in request.REQUEST.keys(): - redirect_url = request.REQUEST['redirect_url'] - return HttpResponse(jinja_environ.get_template('redirect.html').render({"pcuser":None,"redirect_url":redirect_url})) - - username = request.REQUEST['username'] - password = request.REQUEST['password'] - confirmpassword = request.REQUEST['confirmpassword'] - - if password <> confirmpassword: - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'

    Passwords don\'t match. Please Enter again.

    Click OK to go back to signup page.

    ',"link":'/signup_page/'})) - - first_name = request.REQUEST['first_name'] - last_name = request.REQUEST['last_name'] - phone = request.REQUEST['phone'] - email = request.REQUEST['email'] - gender = request.REQUEST['gender'] - location = request.REQUEST['location'] - - try: - if len(User.objects.filter(email=email))<>0: - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'

    Someone has already registered using this email.

    If you have forgotten your password, click

    Click here to go back to signup page.

    ',"link":'0'})) - except: - pass - - if '@' not in email or '.' not in email: - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'

    Invalid email, please Enter again.

    Go Back or click OK to go to signup page.

    ',"link":"/signup_page/"})) - - - if first_name == "": - first_name = username - - user = User.objects.create_user(username, email, password) - user.first_name = first_name - user.last_name = last_name - user.save() - entry = Pcuser(user=user, phone=phone, gender=gender, location=location, verified = uuid.uuid4().hex) - - entry.save() - #send email to user - login_do(request) - send_verification_email(request) - - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'

    Verification email sent. check your inbox and verify the account.

    ',"text1":'

    Go Back or click OK to go to signup page.

    ',"link":'/signup_page/'})) - + template_name = 'ui/dashboard.html' + def get_context_data(self, **kwargs): + context = super(DashboardView, self).get_context_data(*kwargs) + try: + context['pcuser'] = self.request.user.pcuser + except: + context['pcuser'] = None + return context + + +# Information about PeaceCorps in the footer section +class AboutPC(TemplateView): -#Function to send verification mail to user's email after he signs up. -def send_verification_email(request): - if not request.user.is_authenticated(): - return HttpResponse(jinja_environ.get_template('index.html').render({"pcuser":None})) - - try: - request.user.pcuser - except: - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'No Pcuser associated!. Please go back or click to go to the homepage' , "link": '/'})) - entry=request.user - subject = 'Peace Corps Verification Email' - msg = 'Subject: %s \n\nYour email has been registered on pchub.com.\nPlease\ - click on the following link to verify (or copy paste it in your browser if needed)\n\n\ - %s/verify?code=%s\n\nIf you have not registered on our website, please ignore.' % (subject, website, entry.pcuser.verified) - - x = send_email(msg, entry.email) - if x[0]==0: - return x[1] - - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, "text":'

    Verification Email sent! Please Check your email inbox.

    To re-send verification email, click here.

    Click here to go to the homepage and log-in again

    ', "link":'0'})) + template_name = 'ui/aboutPC.html' + def get_context_data(self, **kwargs): + context = super(AboutPC, self).get_context_data(*kwargs) + try: + context['pcuser'] = self.request.user.pcuser + except: + context['pcuser'] = None + return context -#Function to send emails using google smtplib. Takes email id and message as input. -def send_email(msg, email): - gmailLogin = 'pc.mobile.control.center' - gmailPas = 'alphadeltaepsilon' - fro = gmailLogin + "@gmail.com" - - to = email - - server = smtplib.SMTP_SSL('smtp.googlemail.com',SMTP_PORT) - a = server.login( gmailLogin, gmailPas) - server.sendmail(fro, to,msg) - return (1,1) - - -#Called when a user enters verification code and clicks on submit. Checks the verification code with database. -def verify(request): - if not request.user.is_authenticated(): - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'Verification Successful.',"text1":'Go to homepage' , "link": '/'})) -# return HttpResponse(jinja_environ.get_template('index.html').render({"pcuser":Non, -# "code":request.REQUEST['code']})) -# index(request) - try: - request.user.pcuser - except: - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'

    No Pcuser associated.

    ',"text1":'

    Please click here to go to the homepage

    ',"link":'/'})) - - code = request.REQUEST['code'] - pcuser = request.user.pcuser - if pcuser.verified == '1': - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, - "text":'

    Verification successful.

    ',"text1":'

    Click here to go to the homepage

    ',"link":'/'})) - elif code == pcuser.verified: - pcuser.verified = '1' - pcuser.save() - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, - "text":'

    Verification successful.

    ',"text1":'

    Click here to go to the homepage

    ',"link":'/'})) +# PeaceCorps policies in the footer section +class Policies(TemplateView): - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, - "text":'

    Verification Failed.

    ',"text1":'

    Please go back or click here to go to the homepage

    ',"link":'/'})) + template_name = 'ui/policies.html' + def get_context_data(self, **kwargs): + context = super(Policies, self).get_context_data(*kwargs) + try: + context['pcuser'] = self.request.user.pcuser + except: + context['pcuser'] = None + return context - -#Called when a user clicks login button. -@csrf_exempt -def login_do(request): - username = request.REQUEST['username'] - password = request.REQUEST['password'] - user = authenticate(username=username, password=password) - - if user is not None: - if user.is_active: - login(request, user) - if 'redirect' in request.REQUEST.keys(): - return HttpResponse(jinja_environ.get_template('redirect.html').render({"pcuser":None,"redirect_url":request.REQUEST['redirect'].replace("!!__!!","&")})) - return HttpResponse(jinja_environ.get_template('redirect.html').render({"pcuser":None,"redirect_url":"/"})) - - else: - # Return an 'invalid login' error message. - if "js" in request.REQUEST.keys(): - if len(User.objects.filter(username=request.REQUEST['username'])) == 0: - return HttpResponse("inv_user") - return HttpResponse("inv_pass") - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'Invalid Login.', "text1":'Click here to go to home page.',"link":'/'})) - - -#Called when a user clicks logout button. -def logout_do(request): - logout(request) - redirect_url = "/" - if 'redirect_url' in request.REQUEST.keys(): - redirect_url = request.REQUEST['redirect_url'] - return HttpResponse(jinja_environ.get_template('redirect.html').render({"pcuser":None,"redirect_url":redirect_url})) +# PeaceCorps details in the footer section +class Details(TemplateView): - -def profile(request): - - try: - pcuserid = request.REQUEST['id'] - if pcuserid == request.user.pcuser.pk: - return HttpResponse(jinja_environ.get_template('profile.html').render({"pcuser":request.user.pcuser, "profiler":request.user.pcuser})) - else: - return HttpResponse(jinja_environ.get_template('profile.html').render({"pcuser":request.user.pcuser, "profiler":Pcuser.objects.get(pk=pcuserid)})) - except: - return HttpResponse(jinja_environ.get_template('profile.html').render({"pcuser":request.user.pcuser, "profiler":request.user.pcuser})) - - -#Calls the edit profile page. The autofill data is sent too. -def edit_profile_page(request): - if not request.user.is_authenticated(): - return HttpResponse(jinja_environ.get_template('index.html').render({"pcuser":None})) - pcuserid = request.REQUEST['id'] - return HttpResponse(jinja_environ.get_template('edit_profile.html').render({"pcuser":Pcuser.objects.get(pk=pcuserid)})) - -#Edit profile function. Called after a user presses done in edit profile. New data is requested from frontend and stored. -@csrf_exempt -def edit_profile(request): - if not request.user.is_authenticated(): - return HttpResponse(jinja_environ.get_template('index.html').render({"pcuser":None})) + template_name = 'ui/details.html' - - #To remove profile picture - if 'reset_image' in request.REQUEST.keys(): - request.user.pcuser.image = "http://vfcstatic.r.worldssl.net/assets/car_icon-e0df962a717a5db6ebc8b37e80b05713.png" - if str(request.user.pcuser.imageobj) <> '': - path = '/vagrant/submit/media/propics/' + request.user.username + request.user.pcuser.imageobj.url[request.user.pcuser.imageobj.url.rfind('.'):] - if os.path.isfile(path): - os.remove(path) - request.user.pcuser.save() - return edit_profile_page(request) - - - if 'image' in request.FILES.keys(): - #delete old file - if str(request.user.pcuser.imageobj) <> '': - path = '/vagrant/submit/media/propics/' + request.user.username + ".jpg" - if os.path.isfile(path): - os.remove(path) - request.user.pcuser.imageobj = request.FILES['image'] - request.user.pcuser.image = '/static/' + request.user.username + ".jpg" - - - - - - - request.user.pcuser.gender = request.REQUEST['gender'] - request.user.pcuser.phone = request.REQUEST['phone'] - request.user.pcuser.email = request.REQUEST['email'] - request.user.pcuser.location = request.REQUEST['location'] - request.user.first_name = request.REQUEST['first_name'] - request.user.last_name = request.REQUEST['last_name'] - - request.user.pcuser.save() - - request.user.save() - - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, - "text":'Profile edit successful.',"text1":'Click here to view the profile.',"link":'/profile/?id='+ str(request.user.pcuser.id)})) - -#Forgot Password page call function. -def forgot_pass_page(request): - if request.user.is_authenticated(): - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, - "text":'

    Please log out before requesting reset in password.

    \ -

    Click OK to go to the homepage

    ',"link":'/'})) - return HttpResponse(jinja_environ.get_template('forgot_password.html').render({"pcuser":None})) - - - - -#Called when the user clicks forgot password after the data is validated. This sends a verification mail to the user. -@csrf_exempt -def forgot_pass(request): - if request.user.is_authenticated(): - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'

    Please log out in order to request for a password reset.

    \ -

    Please go back or click here to go to the homepage

    ',"link":'/'})) - if 'username' not in request.REQUEST.keys() or 'email' not in request.REQUEST.keys(): - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'Invalid Request. Please go back or',"text1":'click here to go to the homepage',"link":'/'})) - user = User.objects.filter(username=request.REQUEST['username']) - if len(user) == 0: - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'User Does not exist. Please go back or',"text1":'click here to go to the homepage',"link":'/'})) - user = user[0] - if user.email <> request.REQUEST['email']: - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'Invalid email. Please go back or',"text1":'click here to go to the homepage',"link":'/'})) - user.pcuser.reset_pass = uuid.uuid4().hex - user.pcuser.save() - - subject = "Password Reset Request" - msg = 'Subject: %s \n\nYou have requested for a password reset on Mobile App Control Center\n\ - Please click on the following link (or copy paste in your browser) to reset your password.\n\n\ - %s/reset_pass_page/?reset_pass=%s&email=%s\n\n\ - If you have not requested for a reset of password, please ignore.' % (subject, website, user.pcuser.reset_pass, user.email) - - x = send_email(msg, user.email) - if x[0] == 0: - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'Could not process request, please try again later by going back or',"text1":'clicking here to go to the homepage', "link":'/'})) - else: - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'

    An email has been sent to your regestered email address.

    \ -

    Check your email and click on the link to reset your password.

    ',"text1":'

    Click here to go to the homepage

    ',"link":'/'})) - + def get_context_data(self, **kwargs): + context = super(Details, self).get_context_data(*kwargs) + try: + context['pcuser'] = self.request.user.pcuser + except: + context['pcuser'] = None + return context + +# PeaceCorps help in the footer section +class HelpPC(TemplateView): -#Reset Password page call function. -@csrf_exempt -def reset_pass_page(request): - if request.user.is_authenticated(): - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, - "text":'

    Please log out before requesting reset in password.

    ',"text1":'

    Click here to go to the homepage

    ',"link":'/'})) - if "reset_pass" not in request.REQUEST.keys() or 'email' not in request.REQUEST.keys(): - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'

    Invalid Request

    ',"text1":'Click here to go to the homepage

    ', "link":'/'})) - reset_pass = request.REQUEST['reset_pass'] - if reset_pass == "": - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'

    Invalid Request

    ',"text1":'

    click here to go to the homepage

    ', "link":'/'})) - user = Pcuser.objects.filter(reset_pass=reset_pass) - if len(user)==0: - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'Invalid Request.',"text1":'Please go back or click here to go to the homepage',"link":'/'})) - - user = user[0].user - - if user.email <> request.REQUEST['email']: - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'Invalid Email.',"text1":'Please go back or click here to go to the homepage',"link":'/'})) - return HttpResponse(jinja_environ.get_template('reset_password.html').render({'pcuser':None, 'reset_pass':reset_pass})) - - - -#Called when the user clicks change password button. Checks if the previous password is valid or not. -@csrf_exempt -def change_pass(request): - if "reset_pass" in request.REQUEST.keys(): - reset_pass = request.REQUEST['reset_pass'] - if reset_pass == "": - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'

    Invalid Request

    ', "text1":'

    click here to go to the homepage

    ',"link":'/'})) - user = Pcuser.objects.filter(reset_pass=reset_pass) - if len(user)==0 or 'pass' not in request.REQUEST.keys(): - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'Invalid Request.',"text1":'Please go back or click here to go to the homepage',"link":'/'})) - user = user[0].user - user.set_password(request.REQUEST['pass']) - user.save() - user.pcuser.reset_pass = "" - user.pcuser.save() - logout(request) - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'Password Changed.',"text1":'Please click here to go to the homepage and log in again.',"link":'/logout_do/'})) - else: - retval = check(request) - if retval <> None: - return retval - if "pass" not in request.REQUEST.keys() or "oldpass" not in request.REQUEST.keys(): - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, - "text":'Invalid Request.', "text1":'Please go back or click here to go to the homepage',"link":'/'})) - if not request.user.check_password(request.REQUEST['oldpass']): - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":request.user.pcuser, - "text":'Invalid Old Password.',"text1":'Click here to go to the homepage',"link":'/'})) - request.user.set_password(request.REQUEST['pass']) - request.user.save() - logout(request) - return HttpResponse(jinja_environ.get_template('notice.html').render({"pcuser":None, - "text":'Password Changed.',"text1":'Please click here to go to the homepage and log in again.',"link":'/logout_do/'})) - - - -#Change password page call function -def change_pass_page(request): - retval = check(request) - if retval <> None: - return retval - return HttpResponse(jinja_environ.get_template('change_password.html').render({"pcuser":request.user.pcuser})) - + template_name = 'ui/helpPC.html' -#called when user wishes to go to the about PeaceCorps -def aboutPC(request): - return HttpResponse(jinja_environ.get_template('aboutPC.html').render({"pcuser":None})) + def get_context_data(self, **kwargs): + context = super(HelpPC, self).get_context_data(*kwargs) + try: + context['pcuser'] = self.request.user.pcuser + except: + context['pcuser'] = None + return context -#called when user wishes to go to the Policies -def policies(request): - return HttpResponse(jinja_environ.get_template('policies.html').render({"pcuser":None})) -#called when user wishes to go to the Important details -def details(request): - return HttpResponse(jinja_environ.get_template('details.html').render({"pcuser":None})) +# Search through posts (displayed on the right corner of the dashboard) +class PostSearchView(ListView): -#called when user wishes to go to the Help -def helpPC(request): - return HttpResponse(jinja_environ.get_template('helpPC.html').render({"pcuser":None})) + template_name = 'ui/result.html' + model = Post -#called to test if the script is fetching data from the excel sheet -def testDB(request): - book = xlrd.open_workbook("Updated Project Framework Indicator List PeaceTrack.xlsx") - no = book.nsheets - - return HttpResponse(jinja_environ.get_template('test.html').render({"pcuser":None, "no":no})) + def get_queryset(self): + + result = super(PostSearchView, self).get_queryset() + query = self.request.GET.get('search') + category = self.request.GET.get('category') + + if query: + if category == 'firstaide': + result = ghnPost.objects.filter(title__icontains=query) + elif category == 'firstaide_safety_tools': + result = SafetyToolsPost.objects.filter(title__icontains=query) + elif category == 'malaria': + result = Post.objects.filter(title_post__icontains=query) + else: + result = list(chain(Post.objects.filter(title_post__icontains=query), + ghnPost.objects.filter(title__icontains=query), + SafetyToolsPost.objects.filter(title__icontains=query))) + return result + + def get_context_data(self, **kwargs): + + context = super(PostSearchView, self).get_context_data(*kwargs) + category = self.request.GET.get('category') + context['category'] = category + return context + + +class LoginReal(TemplateView): + template_name="login_real.html" + + +def login_social(request): + username= request.POST['uname'] + user=User.objects.get(username=username) + print(user.email) + print(username) + gender="Restricted" + location= "N.A" + phone="N.A" + num_results = Pcuser.objects.filter(user=user).count() + if num_results ==0: + + print("num rsults") + print(num_results) + + entry = Pcuser(user=user, phone=phone, gender=gender, location=location, verified = uuid.uuid4().hex) + entry.save() + else: + print("num rsults") + print(num_results) + pcuser=Pcuser.objects.get(user=user) + entry=pcuser + + # if 'redirect' in request.POST.keys(): + # return HttpResponse(jinja_environ.get_template('redirect.html').render({"pcuser":None,"redirect_url":request.POST['redirect'].replace("!!__!!","&")})) + # return HttpResponse(jinja_environ.get_template('redirect.html').render({"pcuser":None,"redirect_url":"/"})) + return redirect("dashboard") diff --git a/webhub/xlrd/__init__.py b/webhub/xlrd/__init__.py deleted file mode 100644 index 423a3158..00000000 --- a/webhub/xlrd/__init__.py +++ /dev/null @@ -1,461 +0,0 @@ -from os import path - -from .info import __VERSION__ - -#

    Copyright (c) 2005-2012 Stephen John Machin, Lingfo Pty Ltd

    -#

    This module is part of the xlrd package, which is released under a -# BSD-style licence.

    - -from . import licences - -## -#

    A Python module for extracting data from MS Excel (TM) spreadsheet files. -#

    -# Version 0.7.4 -- April 2012 -#

    -# -#

    General information

    -# -#

    Acknowledgements

    -# -#

    -# Development of this module would not have been possible without the document -# "OpenOffice.org's Documentation of the Microsoft Excel File Format" -# ("OOo docs" for short). -# The latest version is available from OpenOffice.org in -# PDF format -# and -# ODT format. -# Small portions of the OOo docs are reproduced in this -# document. A study of the OOo docs is recommended for those who wish a -# deeper understanding of the Excel file layout than the xlrd docs can provide. -#

    -# -#

    Backporting to Python 2.1 was partially funded by -# -# Journyx - provider of timesheet and project accounting solutions. -# -#

    -# -#

    Provision of formatting information in version 0.6.1 was funded by -# -# Simplistix Ltd. -# -#

    -# -#

    Unicode

    -# -#

    This module presents all text strings as Python unicode objects. -# From Excel 97 onwards, text in Excel spreadsheets has been stored as Unicode. -# Older files (Excel 95 and earlier) don't keep strings in Unicode; -# a CODEPAGE record provides a codepage number (for example, 1252) which is -# used by xlrd to derive the encoding (for same example: "cp1252") which is -# used to translate to Unicode.

    -# -#

    If the CODEPAGE record is missing (possible if the file was created -# by third-party software), xlrd will assume that the encoding is ascii, and keep going. -# If the actual encoding is not ascii, a UnicodeDecodeError exception will be raised and -# you will need to determine the encoding yourself, and tell xlrd: -#

    -#     book = xlrd.open_workbook(..., encoding_override="cp1252")
    -# 

    -#

    If the CODEPAGE record exists but is wrong (for example, the codepage -# number is 1251, but the strings are actually encoded in koi8_r), -# it can be overridden using the same mechanism. -# The supplied runxlrd.py has a corresponding command-line argument, which -# may be used for experimentation: -#

    -#     runxlrd.py -e koi8_r 3rows myfile.xls
    -# 

    -#

    The first place to look for an encoding ("codec name") is -# -# the Python documentation. -#

    -#
    -# -#

    Dates in Excel spreadsheets

    -# -#

    In reality, there are no such things. What you have are floating point -# numbers and pious hope. -# There are several problems with Excel dates:

    -# -#

    (1) Dates are not stored as a separate data type; they are stored as -# floating point numbers and you have to rely on -# (a) the "number format" applied to them in Excel and/or -# (b) knowing which cells are supposed to have dates in them. -# This module helps with (a) by inspecting the -# format that has been applied to each number cell; -# if it appears to be a date format, the cell -# is classified as a date rather than a number. Feedback on this feature, -# especially from non-English-speaking locales, would be appreciated.

    -# -#

    (2) Excel for Windows stores dates by default as the number of -# days (or fraction thereof) since 1899-12-31T00:00:00. Excel for -# Macintosh uses a default start date of 1904-01-01T00:00:00. The date -# system can be changed in Excel on a per-workbook basis (for example: -# Tools -> Options -> Calculation, tick the "1904 date system" box). -# This is of course a bad idea if there are already dates in the -# workbook. There is no good reason to change it even if there are no -# dates in the workbook. Which date system is in use is recorded in the -# workbook. A workbook transported from Windows to Macintosh (or vice -# versa) will work correctly with the host Excel. When using this -# module's xldate_as_tuple function to convert numbers from a workbook, -# you must use the datemode attribute of the Book object. If you guess, -# or make a judgement depending on where you believe the workbook was -# created, you run the risk of being 1462 days out of kilter.

    -# -#

    Reference: -# http://support.microsoft.com/default.aspx?scid=KB;EN-US;q180162

    -# -# -#

    (3) The Excel implementation of the Windows-default 1900-based date system works on the -# incorrect premise that 1900 was a leap year. It interprets the number 60 as meaning 1900-02-29, -# which is not a valid date. Consequently any number less than 61 is ambiguous. Example: is 59 the -# result of 1900-02-28 entered directly, or is it 1900-03-01 minus 2 days? The OpenOffice.org Calc -# program "corrects" the Microsoft problem; entering 1900-02-27 causes the number 59 to be stored. -# Save as an XLS file, then open the file with Excel -- you'll see 1900-02-28 displayed.

    -# -#

    Reference: http://support.microsoft.com/default.aspx?scid=kb;en-us;214326

    -# -#

    (4) The Macintosh-default 1904-based date system counts 1904-01-02 as day 1 and 1904-01-01 as day zero. -# Thus any number such that (0.0 <= number < 1.0) is ambiguous. Is 0.625 a time of day (15:00:00), -# independent of the calendar, -# or should it be interpreted as an instant on a particular day (1904-01-01T15:00:00)? -# The xldate_* functions in this module -# take the view that such a number is a calendar-independent time of day (like Python's datetime.time type) for both -# date systems. This is consistent with more recent Microsoft documentation -# (for example, the help file for Excel 2002 which says that the first day -# in the 1904 date system is 1904-01-02). -# -#

    (5) Usage of the Excel DATE() function may leave strange dates in a spreadsheet. Quoting the help file, -# in respect of the 1900 date system: "If year is between 0 (zero) and 1899 (inclusive), -# Excel adds that value to 1900 to calculate the year. For example, DATE(108,1,2) returns January 2, 2008 (1900+108)." -# This gimmick, semi-defensible only for arguments up to 99 and only in the pre-Y2K-awareness era, -# means that DATE(1899, 12, 31) is interpreted as 3799-12-31.

    -# -#

    For further information, please refer to the documentation for the xldate_* functions.

    -# -#

    Named references, constants, formulas, and macros

    -# -#

    -# A name is used to refer to a cell, a group of cells, a constant -# value, a formula, or a macro. Usually the scope of a name is global -# across the whole workbook. However it can be local to a worksheet. -# For example, if the sales figures are in different cells in -# different sheets, the user may define the name "Sales" in each -# sheet. There are built-in names, like "Print_Area" and -# "Print_Titles"; these two are naturally local to a sheet. -#

    -# To inspect the names with a user interface like MS Excel, OOo Calc, -# or Gnumeric, click on Insert/Names/Define. This will show the global -# names, plus those local to the currently selected sheet. -#

    -# A Book object provides two dictionaries (name_map and -# name_and_scope_map) and a list (name_obj_list) which allow various -# ways of accessing the Name objects. There is one Name object for -# each NAME record found in the workbook. Name objects have many -# attributes, several of which are relevant only when obj.macro is 1. -#

    -# In the examples directory you will find namesdemo.xls which -# showcases the many different ways that names can be used, and -# xlrdnamesAPIdemo.py which offers 3 different queries for inspecting -# the names in your files, and shows how to extract whatever a name is -# referring to. There is currently one "convenience method", -# Name.cell(), which extracts the value in the case where the name -# refers to a single cell. More convenience methods are planned. The -# source code for Name.cell (in __init__.py) is an extra source of -# information on how the Name attributes hang together. -#

    -# -#

    Name information is not extracted from files older than -# Excel 5.0 (Book.biff_version < 50)

    -# -#

    Formatting

    -# -#

    Introduction

    -# -#

    This collection of features, new in xlrd version 0.6.1, is intended -# to provide the information needed to (1) display/render spreadsheet contents -# (say) on a screen or in a PDF file, and (2) copy spreadsheet data to another -# file without losing the ability to display/render it.

    -# -#

    The Palette; Colour Indexes

    -# -#

    A colour is represented in Excel as a (red, green, blue) ("RGB") tuple -# with each component in range(256). However it is not possible to access an -# unlimited number of colours; each spreadsheet is limited to a palette of 64 different -# colours (24 in Excel 3.0 and 4.0, 8 in Excel 2.0). Colours are referenced by an index -# ("colour index") into this palette. -# -# Colour indexes 0 to 7 represent 8 fixed built-in colours: black, white, red, green, blue, -# yellow, magenta, and cyan.

    -# -# The remaining colours in the palette (8 to 63 in Excel 5.0 and later) -# can be changed by the user. In the Excel 2003 UI, Tools/Options/Color presents a palette -# of 7 rows of 8 colours. The last two rows are reserved for use in charts.
    -# The correspondence between this grid and the assigned -# colour indexes is NOT left-to-right top-to-bottom.
    -# Indexes 8 to 15 correspond to changeable -# parallels of the 8 fixed colours -- for example, index 7 is forever cyan; -# index 15 starts off being cyan but can be changed by the user.
    -# -# The default colour for each index depends on the file version; tables of the defaults -# are available in the source code. If the user changes one or more colours, -# a PALETTE record appears in the XLS file -- it gives the RGB values for *all* changeable -# indexes.
    -# Note that colours can be used in "number formats": "[CYAN]...." and "[COLOR8]...." refer -# to colour index 7; "[COLOR16]...." will produce cyan -# unless the user changes colour index 15 to something else.
    -# -#

    In addition, there are several "magic" colour indexes used by Excel:
    -# 0x18 (BIFF3-BIFF4), 0x40 (BIFF5-BIFF8): System window text colour for border lines -# (used in XF, CF, and WINDOW2 records)
    -# 0x19 (BIFF3-BIFF4), 0x41 (BIFF5-BIFF8): System window background colour for pattern background -# (used in XF and CF records )
    -# 0x43: System face colour (dialogue background colour)
    -# 0x4D: System window text colour for chart border lines
    -# 0x4E: System window background colour for chart areas
    -# 0x4F: Automatic colour for chart border lines (seems to be always Black)
    -# 0x50: System ToolTip background colour (used in note objects)
    -# 0x51: System ToolTip text colour (used in note objects)
    -# 0x7FFF: System window text colour for fonts (used in FONT and CF records)
    -# Note 0x7FFF appears to be the *default* colour index. It appears quite often in FONT -# records.
    -# -#

    Default Formatting

    -# -# Default formatting is applied to all empty cells (those not described by a cell record). -# Firstly row default information (ROW record, Rowinfo class) is used if available. -# Failing that, column default information (COLINFO record, Colinfo class) is used if available. -# As a last resort the worksheet/workbook default cell format will be used; this -# should always be present in an Excel file, -# described by the XF record with the fixed index 15 (0-based). By default, it uses the -# worksheet/workbook default cell style, described by the very first XF record (index 0). -# -#

    Formatting features not included in xlrd version 0.6.1

    -#
      -#
    • Rich text i.e. strings containing partial bold italic -# and underlined text, change of font inside a string, etc. -# See OOo docs s3.4 and s3.2. -# Rich text is included in version 0.7.2
    • -#
    • Asian phonetic text (known as "ruby"), used for Japanese furigana. See OOo docs -# s3.4.2 (p15)
    • -#
    • Conditional formatting. See OOo docs -# s5.12, s6.21 (CONDFMT record), s6.16 (CF record)
    • -#
    • Miscellaneous sheet-level and book-level items e.g. printing layout, screen panes.
    • -#
    • Modern Excel file versions don't keep most of the built-in -# "number formats" in the file; Excel loads formats according to the -# user's locale. Currently xlrd's emulation of this is limited to -# a hard-wired table that applies to the US English locale. This may mean -# that currency symbols, date order, thousands separator, decimals separator, etc -# are inappropriate. Note that this does not affect users who are copying XLS -# files, only those who are visually rendering cells.
    • -#
    -# -#

    Loading worksheets on demand

    -# -#

    This feature, new in version 0.7.1, is governed by the on_demand argument -# to the open_workbook() function and allows saving memory and time by loading -# only those sheets that the caller is interested in, and releasing sheets -# when no longer required.

    -# -#

    on_demand=False (default): No change. open_workbook() loads global data -# and all sheets, releases resources no longer required (principally the -# str or mmap object containing the Workbook stream), and returns.

    -# -#

    on_demand=True and BIFF version < 5.0: A warning message is emitted, -# on_demand is recorded as False, and the old process is followed.

    -# -#

    on_demand=True and BIFF version >= 5.0: open_workbook() loads global -# data and returns without releasing resources. At this stage, the only -# information available about sheets is Book.nsheets and Book.sheet_names().

    -# -#

    Book.sheet_by_name() and Book.sheet_by_index() will load the requested -# sheet if it is not already loaded.

    -# -#

    Book.sheets() will load all/any unloaded sheets.

    -# -#

    The caller may save memory by calling -# Book.unload_sheet(sheet_name_or_index) when finished with the sheet. -# This applies irrespective of the state of on_demand.

    -# -#

    The caller may re-load an unloaded sheet by calling Book.sheet_by_xxxx() -# -- except if those required resources have been released (which will -# have happened automatically when on_demand is false). This is the only -# case where an exception will be raised.

    -# -#

    The caller may query the state of a sheet: -# Book.sheet_loaded(sheet_name_or_index) -> a bool

    -# -#

    Book.release_resources() may used to save memory and close -# any memory-mapped file before proceding to examine already-loaded -# sheets. Once resources are released, no further sheets can be loaded.

    -# -#

    When using on-demand, it is advisable to ensure that -# Book.release_resources() is always called even if an exception -# is raised in your own code; otherwise if the input file has been -# memory-mapped, the mmap.mmap object will not be closed and you will -# not be able to access the physical file until your Python process -# terminates. This can be done by calling Book.release_resources() -# explicitly in the finally suite of a try/finally block. -# New in xlrd 0.7.2: the Book object is a "context manager", so if -# using Python 2.5 or later, you can wrap your code in a "with" -# statement.

    -## - -import sys, zipfile, pprint -from . import timemachine -from .biffh import ( - XLRDError, - biff_text_from_num, - error_text_from_code, - XL_CELL_BLANK, - XL_CELL_TEXT, - XL_CELL_BOOLEAN, - XL_CELL_ERROR, - XL_CELL_EMPTY, - XL_CELL_DATE, - XL_CELL_NUMBER - ) -from .formula import * # is constrained by __all__ -from .book import Book, colname #### TODO #### formula also has `colname` (restricted to 256 cols) -from .sheet import empty_cell -from .xldate import XLDateError, xldate_as_tuple - -if sys.version.startswith("IronPython"): - # print >> sys.stderr, "...importing encodings" - import encodings - -try: - import mmap - MMAP_AVAILABLE = 1 -except ImportError: - MMAP_AVAILABLE = 0 -USE_MMAP = MMAP_AVAILABLE - -## -# -# Open a spreadsheet file for data extraction. -# -# @param filename The path to the spreadsheet file to be opened. -# -# @param logfile An open file to which messages and diagnostics are written. -# -# @param verbosity Increases the volume of trace material written to the logfile. -# -# @param use_mmap Whether to use the mmap module is determined heuristically. -# Use this arg to override the result. Current heuristic: mmap is used if it exists. -# -# @param file_contents ... as a string or an mmap.mmap object or some other behave-alike object. -# If file_contents is supplied, filename will not be used, except (possibly) in messages. -# -# @param encoding_override Used to overcome missing or bad codepage information -# in older-version files. Refer to discussion in the Unicode section above. -#
    -- New in version 0.6.0 -# -# @param formatting_info Governs provision of a reference to an XF (eXtended Format) object -# for each cell in the worksheet. -#
    Default is False. This is backwards compatible and saves memory. -# "Blank" cells (those with their own formatting information but no data) are treated as empty -# (by ignoring the file's BLANK and MULBLANK records). -# It cuts off any bottom "margin" of rows of empty (and blank) cells and -# any right "margin" of columns of empty (and blank) cells. -# Only cell_value and cell_type are available. -#
    True provides all cells, including empty and blank cells. -# XF information is available for each cell. -#
    -- New in version 0.6.1 -# -# @param on_demand Governs whether sheets are all loaded initially or when demanded -# by the caller. Please refer back to the section "Loading worksheets on demand" for details. -#
    -- New in version 0.7.1 -# -# @param ragged_rows False (the default) means all rows are padded out with empty cells so that all -# rows have the same size (Sheet.ncols). True means that there are no empty cells at the ends of rows. -# This can result in substantial memory savings if rows are of widely varying sizes. See also the -# Sheet.row_len() method. -#
    -- New in version 0.7.2 -# -# @return An instance of the Book class. - -def open_workbook(filename=None, - logfile=sys.stdout, - verbosity=0, - use_mmap=USE_MMAP, - file_contents=None, - encoding_override=None, - formatting_info=False, - on_demand=False, - ragged_rows=False, - ): - peeksz = 4 - if file_contents: - peek = file_contents[:peeksz] - else: - f = open(filename, "rb") - peek = f.read(peeksz) - f.close() - if peek == b"PK\x03\x04": # a ZIP file - if file_contents: - zf = zipfile.ZipFile(timemachine.BYTES_IO(file_contents)) - else: - zf = zipfile.ZipFile(filename) - component_names = zf.namelist() - if verbosity: - logfile.write('ZIP component_names:\n') - pprint.pprint(component_names, logfile) - if 'xl/workbook.xml' in component_names: - from . import xlsx - bk = xlsx.open_workbook_2007_xml( - zf, - component_names, - logfile=logfile, - verbosity=verbosity, - use_mmap=use_mmap, - formatting_info=formatting_info, - on_demand=on_demand, - ragged_rows=ragged_rows, - ) - return bk - if 'xl/workbook.bin' in component_names: - raise XLRDError('Excel 2007 xlsb file; not supported') - if 'content.xml' in component_names: - raise XLRDError('Openoffice.org ODS file; not supported') - raise XLRDError('ZIP file contents not a known type of workbook') - - from . import book - bk = book.open_workbook_xls( - filename=filename, - logfile=logfile, - verbosity=verbosity, - use_mmap=use_mmap, - file_contents=file_contents, - encoding_override=encoding_override, - formatting_info=formatting_info, - on_demand=on_demand, - ragged_rows=ragged_rows, - ) - return bk - -## -# For debugging: dump an XLS file's BIFF records in char & hex. -# @param filename The path to the file to be dumped. -# @param outfile An open file, to which the dump is written. -# @param unnumbered If true, omit offsets (for meaningful diffs). - -def dump(filename, outfile=sys.stdout, unnumbered=False): - from .biffh import biff_dump - bk = Book() - bk.biff2_8_load(filename=filename, logfile=outfile, ) - biff_dump(bk.mem, bk.base, bk.stream_len, 0, outfile, unnumbered) - -## -# For debugging and analysis: summarise the file's BIFF records. -# I.e. produce a sorted file of (record_name, count). -# @param filename The path to the file to be summarised. -# @param outfile An open file, to which the summary is written. - -def count_records(filename, outfile=sys.stdout): - from .biffh import biff_count_records - bk = Book() - bk.biff2_8_load(filename=filename, logfile=outfile, ) - biff_count_records(bk.mem, bk.base, bk.stream_len, outfile) diff --git a/webhub/xlrd/__init__.pyc b/webhub/xlrd/__init__.pyc deleted file mode 100644 index 301274a9..00000000 Binary files a/webhub/xlrd/__init__.pyc and /dev/null differ diff --git a/webhub/xlrd/biffh.py b/webhub/xlrd/biffh.py deleted file mode 100644 index f3a6d4df..00000000 --- a/webhub/xlrd/biffh.py +++ /dev/null @@ -1,663 +0,0 @@ -# -*- coding: cp1252 -*- - -## -# Support module for the xlrd package. -# -#

    Portions copyright 2005-2010 Stephen John Machin, Lingfo Pty Ltd

    -#

    This module is part of the xlrd package, which is released under a BSD-style licence.

    -## - -# 2010-03-01 SJM Reading SCL record -# 2010-03-01 SJM Added more record IDs for biff_dump & biff_count -# 2008-02-10 SJM BIFF2 BLANK record -# 2008-02-08 SJM Preparation for Excel 2.0 support -# 2008-02-02 SJM Added suffixes (_B2, _B2_ONLY, etc) on record names for biff_dump & biff_count -# 2007-12-04 SJM Added support for Excel 2.x (BIFF2) files. -# 2007-09-08 SJM Avoid crash when zero-length Unicode string missing options byte. -# 2007-04-22 SJM Remove experimental "trimming" facility. - -from __future__ import print_function - -DEBUG = 0 - -from struct import unpack -import sys -from .timemachine import * - -class XLRDError(Exception): - pass - -## -# Parent of almost all other classes in the package. Defines a common "dump" method -# for debugging. - -class BaseObject(object): - - _repr_these = [] - - ## - # @param f open file object, to which the dump is written - # @param header text to write before the dump - # @param footer text to write after the dump - # @param indent number of leading spaces (for recursive calls) - - def dump(self, f=None, header=None, footer=None, indent=0): - if f is None: - f = sys.stderr - if hasattr(self, "__slots__"): - alist = [] - for attr in self.__slots__: - alist.append((attr, getattr(self, attr))) - else: - alist = self.__dict__.items() - alist = sorted(alist) - pad = " " * indent - if header is not None: print(header, file=f) - list_type = type([]) - dict_type = type({}) - for attr, value in alist: - if getattr(value, 'dump', None) and attr != 'book': - value.dump(f, - header="%s%s (%s object):" % (pad, attr, value.__class__.__name__), - indent=indent+4) - elif attr not in self._repr_these and ( - isinstance(value, list_type) or isinstance(value, dict_type) - ): - print("%s%s: %s, len = %d" % (pad, attr, type(value), len(value)), file=f) - else: - fprintf(f, "%s%s: %r\n", pad, attr, value) - if footer is not None: print(footer, file=f) - -FUN, FDT, FNU, FGE, FTX = range(5) # unknown, date, number, general, text -DATEFORMAT = FDT -NUMBERFORMAT = FNU - -( - XL_CELL_EMPTY, - XL_CELL_TEXT, - XL_CELL_NUMBER, - XL_CELL_DATE, - XL_CELL_BOOLEAN, - XL_CELL_ERROR, - XL_CELL_BLANK, # for use in debugging, gathering stats, etc -) = range(7) - -biff_text_from_num = { - 0: "(not BIFF)", - 20: "2.0", - 21: "2.1", - 30: "3", - 40: "4S", - 45: "4W", - 50: "5", - 70: "7", - 80: "8", - 85: "8X", - } - -## -#

    This dictionary can be used to produce a text version of the internal codes -# that Excel uses for error cells. Here are its contents: -#

    -# 0x00: '#NULL!',  # Intersection of two cell ranges is empty
    -# 0x07: '#DIV/0!', # Division by zero
    -# 0x0F: '#VALUE!', # Wrong type of operand
    -# 0x17: '#REF!',   # Illegal or deleted cell reference
    -# 0x1D: '#NAME?',  # Wrong function or range name
    -# 0x24: '#NUM!',   # Value range overflow
    -# 0x2A: '#N/A',    # Argument or function not available
    -# 

    - -error_text_from_code = { - 0x00: '#NULL!', # Intersection of two cell ranges is empty - 0x07: '#DIV/0!', # Division by zero - 0x0F: '#VALUE!', # Wrong type of operand - 0x17: '#REF!', # Illegal or deleted cell reference - 0x1D: '#NAME?', # Wrong function or range name - 0x24: '#NUM!', # Value range overflow - 0x2A: '#N/A', # Argument or function not available -} - -BIFF_FIRST_UNICODE = 80 - -XL_WORKBOOK_GLOBALS = WBKBLOBAL = 0x5 -XL_WORKBOOK_GLOBALS_4W = 0x100 -XL_WORKSHEET = WRKSHEET = 0x10 - -XL_BOUNDSHEET_WORKSHEET = 0x00 -XL_BOUNDSHEET_CHART = 0x02 -XL_BOUNDSHEET_VB_MODULE = 0x06 - -# XL_RK2 = 0x7e -XL_ARRAY = 0x0221 -XL_ARRAY2 = 0x0021 -XL_BLANK = 0x0201 -XL_BLANK_B2 = 0x01 -XL_BOF = 0x809 -XL_BOOLERR = 0x205 -XL_BOOLERR_B2 = 0x5 -XL_BOUNDSHEET = 0x85 -XL_BUILTINFMTCOUNT = 0x56 -XL_CF = 0x01B1 -XL_CODEPAGE = 0x42 -XL_COLINFO = 0x7D -XL_COLUMNDEFAULT = 0x20 # BIFF2 only -XL_COLWIDTH = 0x24 # BIFF2 only -XL_CONDFMT = 0x01B0 -XL_CONTINUE = 0x3c -XL_COUNTRY = 0x8C -XL_DATEMODE = 0x22 -XL_DEFAULTROWHEIGHT = 0x0225 -XL_DEFCOLWIDTH = 0x55 -XL_DIMENSION = 0x200 -XL_DIMENSION2 = 0x0 -XL_EFONT = 0x45 -XL_EOF = 0x0a -XL_EXTERNNAME = 0x23 -XL_EXTERNSHEET = 0x17 -XL_EXTSST = 0xff -XL_FEAT11 = 0x872 -XL_FILEPASS = 0x2f -XL_FONT = 0x31 -XL_FONT_B3B4 = 0x231 -XL_FORMAT = 0x41e -XL_FORMAT2 = 0x1E # BIFF2, BIFF3 -XL_FORMULA = 0x6 -XL_FORMULA3 = 0x206 -XL_FORMULA4 = 0x406 -XL_GCW = 0xab -XL_HLINK = 0x01B8 -XL_QUICKTIP = 0x0800 -XL_HORIZONTALPAGEBREAKS = 0x1b -XL_INDEX = 0x20b -XL_INTEGER = 0x2 # BIFF2 only -XL_IXFE = 0x44 # BIFF2 only -XL_LABEL = 0x204 -XL_LABEL_B2 = 0x04 -XL_LABELRANGES = 0x15f -XL_LABELSST = 0xfd -XL_LEFTMARGIN = 0x26 -XL_TOPMARGIN = 0x28 -XL_RIGHTMARGIN = 0x27 -XL_BOTTOMMARGIN = 0x29 -XL_HEADER = 0x14 -XL_FOOTER = 0x15 -XL_HCENTER = 0x83 -XL_VCENTER = 0x84 -XL_MERGEDCELLS = 0xE5 -XL_MSO_DRAWING = 0x00EC -XL_MSO_DRAWING_GROUP = 0x00EB -XL_MSO_DRAWING_SELECTION = 0x00ED -XL_MULRK = 0xbd -XL_MULBLANK = 0xbe -XL_NAME = 0x18 -XL_NOTE = 0x1c -XL_NUMBER = 0x203 -XL_NUMBER_B2 = 0x3 -XL_OBJ = 0x5D -XL_PAGESETUP = 0xA1 -XL_PALETTE = 0x92 -XL_PANE = 0x41 -XL_PRINTGRIDLINES = 0x2B -XL_PRINTHEADERS = 0x2A -XL_RK = 0x27e -XL_ROW = 0x208 -XL_ROW_B2 = 0x08 -XL_RSTRING = 0xd6 -XL_SCL = 0x00A0 -XL_SHEETHDR = 0x8F # BIFF4W only -XL_SHEETPR = 0x81 -XL_SHEETSOFFSET = 0x8E # BIFF4W only -XL_SHRFMLA = 0x04bc -XL_SST = 0xfc -XL_STANDARDWIDTH = 0x99 -XL_STRING = 0x207 -XL_STRING_B2 = 0x7 -XL_STYLE = 0x293 -XL_SUPBOOK = 0x1AE # aka EXTERNALBOOK in OOo docs -XL_TABLEOP = 0x236 -XL_TABLEOP2 = 0x37 -XL_TABLEOP_B2 = 0x36 -XL_TXO = 0x1b6 -XL_UNCALCED = 0x5e -XL_UNKNOWN = 0xffff -XL_VERTICALPAGEBREAKS = 0x1a -XL_WINDOW2 = 0x023E -XL_WINDOW2_B2 = 0x003E -XL_WRITEACCESS = 0x5C -XL_WSBOOL = XL_SHEETPR -XL_XF = 0xe0 -XL_XF2 = 0x0043 # BIFF2 version of XF record -XL_XF3 = 0x0243 # BIFF3 version of XF record -XL_XF4 = 0x0443 # BIFF4 version of XF record - -boflen = {0x0809: 8, 0x0409: 6, 0x0209: 6, 0x0009: 4} -bofcodes = (0x0809, 0x0409, 0x0209, 0x0009) - -XL_FORMULA_OPCODES = (0x0006, 0x0406, 0x0206) - -_cell_opcode_list = [ - XL_BOOLERR, - XL_FORMULA, - XL_FORMULA3, - XL_FORMULA4, - XL_LABEL, - XL_LABELSST, - XL_MULRK, - XL_NUMBER, - XL_RK, - XL_RSTRING, - ] -_cell_opcode_dict = {} -for _cell_opcode in _cell_opcode_list: - _cell_opcode_dict[_cell_opcode] = 1 - -def is_cell_opcode(c): - return c in _cell_opcode_dict - -def upkbits(tgt_obj, src, manifest, local_setattr=setattr): - for n, mask, attr in manifest: - local_setattr(tgt_obj, attr, (src & mask) >> n) - -def upkbitsL(tgt_obj, src, manifest, local_setattr=setattr, local_int=int): - for n, mask, attr in manifest: - local_setattr(tgt_obj, attr, local_int((src & mask) >> n)) - -def unpack_string(data, pos, encoding, lenlen=1): - nchars = unpack('<' + 'BH'[lenlen-1], data[pos:pos+lenlen])[0] - pos += lenlen - return unicode(data[pos:pos+nchars], encoding) - -def unpack_string_update_pos(data, pos, encoding, lenlen=1, known_len=None): - if known_len is not None: - # On a NAME record, the length byte is detached from the front of the string. - nchars = known_len - else: - nchars = unpack('<' + 'BH'[lenlen-1], data[pos:pos+lenlen])[0] - pos += lenlen - newpos = pos + nchars - return (unicode(data[pos:newpos], encoding), newpos) - -def unpack_unicode(data, pos, lenlen=2): - "Return unicode_strg" - nchars = unpack('<' + 'BH'[lenlen-1], data[pos:pos+lenlen])[0] - if not nchars: - # Ambiguous whether 0-length string should have an "options" byte. - # Avoid crash if missing. - return UNICODE_LITERAL("") - pos += lenlen - options = BYTES_ORD(data[pos]) - pos += 1 - # phonetic = options & 0x04 - # richtext = options & 0x08 - if options & 0x08: - # rt = unpack(' endpos=%d pos=%d endsub=%d substrg=%r\n', - ofs, dlen, base, endpos, pos, endsub, substrg) - break - hexd = ''.join(["%02x " % BYTES_ORD(c) for c in substrg]) - - chard = '' - for c in substrg: - c = chr(BYTES_ORD(c)) - if c == '\0': - c = '~' - elif not (' ' <= c <= '~'): - c = '?' - chard += c - if numbered: - num_prefix = "%5d: " % (base+pos-ofs) - - fprintf(fout, "%s %-48s %s\n", num_prefix, hexd, chard) - pos = endsub - -def biff_dump(mem, stream_offset, stream_len, base=0, fout=sys.stdout, unnumbered=False): - pos = stream_offset - stream_end = stream_offset + stream_len - adj = base - stream_offset - dummies = 0 - numbered = not unnumbered - num_prefix = '' - while stream_end - pos >= 4: - rc, length = unpack('') - if numbered: - num_prefix = "%5d: " % (adj + pos) - fprintf(fout, "%s%04x %s len = %04x (%d)\n", num_prefix, rc, recname, length, length) - pos += 4 - hex_char_dump(mem, pos, length, adj+pos, fout, unnumbered) - pos += length - if dummies: - if numbered: - num_prefix = "%5d: " % (adj + savpos) - fprintf(fout, "%s---- %d zero bytes skipped ----\n", num_prefix, dummies) - if pos < stream_end: - if numbered: - num_prefix = "%5d: " % (adj + pos) - fprintf(fout, "%s---- Misc bytes at end ----\n", num_prefix) - hex_char_dump(mem, pos, stream_end-pos, adj + pos, fout, unnumbered) - elif pos > stream_end: - fprintf(fout, "Last dumped record has length (%d) that is too large\n", length) - -def biff_count_records(mem, stream_offset, stream_len, fout=sys.stdout): - pos = stream_offset - stream_end = stream_offset + stream_len - tally = {} - while stream_end - pos >= 4: - rc, length = unpack('> sys.stderr, "...importing encodings" - import encodings - -empty_cell = sheet.empty_cell # for exposure to the world ... - -DEBUG = 0 - -USE_FANCY_CD = 1 - -TOGGLE_GC = 0 -import gc -# gc.set_debug(gc.DEBUG_STATS) - -try: - import mmap - MMAP_AVAILABLE = 1 -except ImportError: - MMAP_AVAILABLE = 0 -USE_MMAP = MMAP_AVAILABLE - -MY_EOF = 0xF00BAAA # not a 16-bit number - -SUPBOOK_UNK, SUPBOOK_INTERNAL, SUPBOOK_EXTERNAL, SUPBOOK_ADDIN, SUPBOOK_DDEOLE = range(5) - -SUPPORTED_VERSIONS = (80, 70, 50, 45, 40, 30, 21, 20) - -_code_from_builtin_name = { - "Consolidate_Area": "\x00", - "Auto_Open": "\x01", - "Auto_Close": "\x02", - "Extract": "\x03", - "Database": "\x04", - "Criteria": "\x05", - "Print_Area": "\x06", - "Print_Titles": "\x07", - "Recorder": "\x08", - "Data_Form": "\x09", - "Auto_Activate": "\x0A", - "Auto_Deactivate": "\x0B", - "Sheet_Title": "\x0C", - "_FilterDatabase": "\x0D", - } -builtin_name_from_code = {} -code_from_builtin_name = {} -for _bin, _bic in _code_from_builtin_name.items(): - _bin = UNICODE_LITERAL(_bin) - _bic = UNICODE_LITERAL(_bic) - code_from_builtin_name[_bin] = _bic - builtin_name_from_code[_bic] = _bin -del _bin, _bic, _code_from_builtin_name - -def open_workbook_xls(filename=None, - logfile=sys.stdout, verbosity=0, use_mmap=USE_MMAP, - file_contents=None, - encoding_override=None, - formatting_info=False, on_demand=False, ragged_rows=False, - ): - t0 = time.clock() - if TOGGLE_GC: - orig_gc_enabled = gc.isenabled() - if orig_gc_enabled: - gc.disable() - bk = Book() - try: - bk.biff2_8_load( - filename=filename, file_contents=file_contents, - logfile=logfile, verbosity=verbosity, use_mmap=use_mmap, - encoding_override=encoding_override, - formatting_info=formatting_info, - on_demand=on_demand, - ragged_rows=ragged_rows, - ) - t1 = time.clock() - bk.load_time_stage_1 = t1 - t0 - biff_version = bk.getbof(XL_WORKBOOK_GLOBALS) - if not biff_version: - raise XLRDError("Can't determine file's BIFF version") - if biff_version not in SUPPORTED_VERSIONS: - raise XLRDError( - "BIFF version %s is not supported" - % biff_text_from_num[biff_version] - ) - bk.biff_version = biff_version - if biff_version <= 40: - # no workbook globals, only 1 worksheet - if on_demand: - fprintf(bk.logfile, - "*** WARNING: on_demand is not supported for this Excel version.\n" - "*** Setting on_demand to False.\n") - bk.on_demand = on_demand = False - bk.fake_globals_get_sheet() - elif biff_version == 45: - # worksheet(s) embedded in global stream - bk.parse_globals() - if on_demand: - fprintf(bk.logfile, "*** WARNING: on_demand is not supported for this Excel version.\n" - "*** Setting on_demand to False.\n") - bk.on_demand = on_demand = False - else: - bk.parse_globals() - bk._sheet_list = [None for sh in bk._sheet_names] - if not on_demand: - bk.get_sheets() - bk.nsheets = len(bk._sheet_list) - if biff_version == 45 and bk.nsheets > 1: - fprintf(bk.logfile, - "*** WARNING: Excel 4.0 workbook (.XLW) file contains %d worksheets.\n" - "*** Book-level data will be that of the last worksheet.\n", - bk.nsheets - ) - if TOGGLE_GC: - if orig_gc_enabled: - gc.enable() - t2 = time.clock() - bk.load_time_stage_2 = t2 - t1 - except: - bk.release_resources() - raise - # normal exit - if not on_demand: - bk.release_resources() - return bk - -## -# For debugging: dump the file's BIFF records in char & hex. -# @param filename The path to the file to be dumped. -# @param outfile An open file, to which the dump is written. -# @param unnumbered If true, omit offsets (for meaningful diffs). - -def dump(filename, outfile=sys.stdout, unnumbered=False): - bk = Book() - bk.biff2_8_load(filename=filename, logfile=outfile, ) - biff_dump(bk.mem, bk.base, bk.stream_len, 0, outfile, unnumbered) - -## -# For debugging and analysis: summarise the file's BIFF records. -# I.e. produce a sorted file of (record_name, count). -# @param filename The path to the file to be summarised. -# @param outfile An open file, to which the summary is written. - -def count_records(filename, outfile=sys.stdout): - bk = Book() - bk.biff2_8_load(filename=filename, logfile=outfile, ) - biff_count_records(bk.mem, bk.base, bk.stream_len, outfile) - -## -# Information relating to a named reference, formula, macro, etc. -#
    -- New in version 0.6.0 -#
    -- Name information is not extracted from files older than -# Excel 5.0 (Book.biff_version < 50) - -class Name(BaseObject): - - _repr_these = ['stack'] - book = None # parent - - ## - # 0 = Visible; 1 = Hidden - hidden = 0 - - ## - # 0 = Command macro; 1 = Function macro. Relevant only if macro == 1 - func = 0 - - ## - # 0 = Sheet macro; 1 = VisualBasic macro. Relevant only if macro == 1 - vbasic = 0 - - ## - # 0 = Standard name; 1 = Macro name - macro = 0 - - ## - # 0 = Simple formula; 1 = Complex formula (array formula or user defined)
    - # No examples have been sighted. - complex = 0 - - ## - # 0 = User-defined name; 1 = Built-in name - # (common examples: Print_Area, Print_Titles; see OOo docs for full list) - builtin = 0 - - ## - # Function group. Relevant only if macro == 1; see OOo docs for values. - funcgroup = 0 - - ## - # 0 = Formula definition; 1 = Binary data
    No examples have been sighted. - binary = 0 - - ## - # The index of this object in book.name_obj_list - name_index = 0 - - ## - # A Unicode string. If builtin, decoded as per OOo docs. - name = UNICODE_LITERAL("") - - ## - # An 8-bit string. - raw_formula = b'' - - ## - # -1: The name is global (visible in all calculation sheets).
    - # -2: The name belongs to a macro sheet or VBA sheet.
    - # -3: The name is invalid.
    - # 0 <= scope < book.nsheets: The name is local to the sheet whose index is scope. - scope = -1 - - ## - # The result of evaluating the formula, if any. - # If no formula, or evaluation of the formula encountered problems, - # the result is None. Otherwise the result is a single instance of the - # Operand class. - # - result = None - - ## - # This is a convenience method for the frequent use case where the name - # refers to a single cell. - # @return An instance of the Cell class. - # @throws XLRDError The name is not a constant absolute reference - # to a single cell. - def cell(self): - res = self.result - if res: - # result should be an instance of the Operand class - kind = res.kind - value = res.value - if kind == oREF and len(value) == 1: - ref3d = value[0] - if (0 <= ref3d.shtxlo == ref3d.shtxhi - 1 - and ref3d.rowxlo == ref3d.rowxhi - 1 - and ref3d.colxlo == ref3d.colxhi - 1): - sh = self.book.sheet_by_index(ref3d.shtxlo) - return sh.cell(ref3d.rowxlo, ref3d.colxlo) - self.dump(self.book.logfile, - header="=== Dump of Name object ===", - footer="======= End of dump =======", - ) - raise XLRDError("Not a constant absolute reference to a single cell") - - ## - # This is a convenience method for the use case where the name - # refers to one rectangular area in one worksheet. - # @param clipped If true (the default), the returned rectangle is clipped - # to fit in (0, sheet.nrows, 0, sheet.ncols) -- it is guaranteed that - # 0 <= rowxlo <= rowxhi <= sheet.nrows and that the number of usable rows - # in the area (which may be zero) is rowxhi - rowxlo; likewise for columns. - # @return a tuple (sheet_object, rowxlo, rowxhi, colxlo, colxhi). - # @throws XLRDError The name is not a constant absolute reference - # to a single area in a single sheet. - def area2d(self, clipped=True): - res = self.result - if res: - # result should be an instance of the Operand class - kind = res.kind - value = res.value - if kind == oREF and len(value) == 1: # only 1 reference - ref3d = value[0] - if 0 <= ref3d.shtxlo == ref3d.shtxhi - 1: # only 1 usable sheet - sh = self.book.sheet_by_index(ref3d.shtxlo) - if not clipped: - return sh, ref3d.rowxlo, ref3d.rowxhi, ref3d.colxlo, ref3d.colxhi - rowxlo = min(ref3d.rowxlo, sh.nrows) - rowxhi = max(rowxlo, min(ref3d.rowxhi, sh.nrows)) - colxlo = min(ref3d.colxlo, sh.ncols) - colxhi = max(colxlo, min(ref3d.colxhi, sh.ncols)) - assert 0 <= rowxlo <= rowxhi <= sh.nrows - assert 0 <= colxlo <= colxhi <= sh.ncols - return sh, rowxlo, rowxhi, colxlo, colxhi - self.dump(self.book.logfile, - header="=== Dump of Name object ===", - footer="======= End of dump =======", - ) - raise XLRDError("Not a constant absolute reference to a single area in a single sheet") - -## -# Contents of a "workbook". -#

    WARNING: You don't call this class yourself. You use the Book object that -# was returned when you called xlrd.open_workbook("myfile.xls").

    - -class Book(BaseObject): - - ## - # The number of worksheets present in the workbook file. - # This information is available even when no sheets have yet been loaded. - nsheets = 0 - - ## - # Which date system was in force when this file was last saved.
    - # 0 => 1900 system (the Excel for Windows default).
    - # 1 => 1904 system (the Excel for Macintosh default).
    - datemode = 0 # In case it's not specified in the file. - - ## - # Version of BIFF (Binary Interchange File Format) used to create the file. - # Latest is 8.0 (represented here as 80), introduced with Excel 97. - # Earliest supported by this module: 2.0 (represented as 20). - biff_version = 0 - - ## - # List containing a Name object for each NAME record in the workbook. - #
    -- New in version 0.6.0 - name_obj_list = [] - - ## - # An integer denoting the character set used for strings in this file. - # For BIFF 8 and later, this will be 1200, meaning Unicode; more precisely, UTF_16_LE. - # For earlier versions, this is used to derive the appropriate Python encoding - # to be used to convert to Unicode. - # Examples: 1252 -> 'cp1252', 10000 -> 'mac_roman' - codepage = None - - ## - # The encoding that was derived from the codepage. - encoding = None - - ## - # A tuple containing the (telephone system) country code for:
    - # [0]: the user-interface setting when the file was created.
    - # [1]: the regional settings.
    - # Example: (1, 61) meaning (USA, Australia). - # This information may give a clue to the correct encoding for an unknown codepage. - # For a long list of observed values, refer to the OpenOffice.org documentation for - # the COUNTRY record. - countries = (0, 0) - - ## - # What (if anything) is recorded as the name of the last user to save the file. - user_name = UNICODE_LITERAL('') - - ## - # A list of Font class instances, each corresponding to a FONT record. - #
    -- New in version 0.6.1 - font_list = [] - - ## - # A list of XF class instances, each corresponding to an XF record. - #
    -- New in version 0.6.1 - xf_list = [] - - ## - # A list of Format objects, each corresponding to a FORMAT record, in - # the order that they appear in the input file. - # It does not contain builtin formats. - # If you are creating an output file using (for example) pyExcelerator, - # use this list. - # The collection to be used for all visual rendering purposes is format_map. - #
    -- New in version 0.6.1 - format_list = [] - - ## - # The mapping from XF.format_key to Format object. - #
    -- New in version 0.6.1 - format_map = {} - - ## - # This provides access via name to the extended format information for - # both built-in styles and user-defined styles.
    - # It maps name to (built_in, xf_index), where:
    - # name is either the name of a user-defined style, - # or the name of one of the built-in styles. Known built-in names are - # Normal, RowLevel_1 to RowLevel_7, - # ColLevel_1 to ColLevel_7, Comma, Currency, Percent, "Comma [0]", - # "Currency [0]", Hyperlink, and "Followed Hyperlink".
    - # built_in 1 = built-in style, 0 = user-defined
    - # xf_index is an index into Book.xf_list.
    - # References: OOo docs s6.99 (STYLE record); Excel UI Format/Style - #
    -- New in version 0.6.1; since 0.7.4, extracted only if - # open_workbook(..., formatting_info=True) - style_name_map = {} - - ## - # This provides definitions for colour indexes. Please refer to the - # above section "The Palette; Colour Indexes" for an explanation - # of how colours are represented in Excel.
    - # Colour indexes into the palette map into (red, green, blue) tuples. - # "Magic" indexes e.g. 0x7FFF map to None. - # colour_map is what you need if you want to render cells on screen or in a PDF - # file. If you are writing an output XLS file, use palette_record. - #
    -- New in version 0.6.1. Extracted only if open_workbook(..., formatting_info=True) - colour_map = {} - - ## - # If the user has changed any of the colours in the standard palette, the XLS - # file will contain a PALETTE record with 56 (16 for Excel 4.0 and earlier) - # RGB values in it, and this list will be e.g. [(r0, b0, g0), ..., (r55, b55, g55)]. - # Otherwise this list will be empty. This is what you need if you are - # writing an output XLS file. If you want to render cells on screen or in a PDF - # file, use colour_map. - #
    -- New in version 0.6.1. Extracted only if open_workbook(..., formatting_info=True) - palette_record = [] - - ## - # Time in seconds to extract the XLS image as a contiguous string (or mmap equivalent). - load_time_stage_1 = -1.0 - - ## - # Time in seconds to parse the data from the contiguous string (or mmap equivalent). - load_time_stage_2 = -1.0 - - ## - # @return A list of all sheets in the book. - # All sheets not already loaded will be loaded. - def sheets(self): - for sheetx in xrange(self.nsheets): - if not self._sheet_list[sheetx]: - self.get_sheet(sheetx) - return self._sheet_list[:] - - ## - # @param sheetx Sheet index in range(nsheets) - # @return An object of the Sheet class - def sheet_by_index(self, sheetx): - return self._sheet_list[sheetx] or self.get_sheet(sheetx) - - ## - # @param sheet_name Name of sheet required - # @return An object of the Sheet class - def sheet_by_name(self, sheet_name): - try: - sheetx = self._sheet_names.index(sheet_name) - except ValueError: - raise XLRDError('No sheet named <%r>' % sheet_name) - return self.sheet_by_index(sheetx) - - ## - # @return A list of the names of all the worksheets in the workbook file. - # This information is available even when no sheets have yet been loaded. - def sheet_names(self): - return self._sheet_names[:] - - ## - # @param sheet_name_or_index Name or index of sheet enquired upon - # @return true if sheet is loaded, false otherwise - #
    -- New in version 0.7.1 - def sheet_loaded(self, sheet_name_or_index): - if isinstance(sheet_name_or_index, int): - sheetx = sheet_name_or_index - else: - try: - sheetx = self._sheet_names.index(sheet_name_or_index) - except ValueError: - raise XLRDError('No sheet named <%r>' % sheet_name_or_index) - return bool(self._sheet_list[sheetx]) - - ## - # @param sheet_name_or_index Name or index of sheet to be unloaded. - #
    -- New in version 0.7.1 - def unload_sheet(self, sheet_name_or_index): - if isinstance(sheet_name_or_index, int): - sheetx = sheet_name_or_index - else: - try: - sheetx = self._sheet_names.index(sheet_name_or_index) - except ValueError: - raise XLRDError('No sheet named <%r>' % sheet_name_or_index) - self._sheet_list[sheetx] = None - - ## - # This method has a dual purpose. You can call it to release - # memory-consuming objects and (possibly) a memory-mapped file - # (mmap.mmap object) when you have finished loading sheets in - # on_demand mode, but still require the Book object to examine the - # loaded sheets. It is also called automatically (a) when open_workbook - # raises an exception and (b) if you are using a "with" statement, when - # the "with" block is exited. Calling this method multiple times on the - # same object has no ill effect. - def release_resources(self): - self._resources_released = 1 - if hasattr(self.mem, "close"): - # must be a mmap.mmap object - self.mem.close() - self.mem = None - if hasattr(self.filestr, "close"): - self.filestr.close() - self.filestr = None - self._sharedstrings = None - self._rich_text_runlist_map = None - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, exc_tb): - self.release_resources() - # return false - - ## - # A mapping from (lower_case_name, scope) to a single Name object. - #
    -- New in version 0.6.0 - name_and_scope_map = {} - - ## - # A mapping from lower_case_name to a list of Name objects. The list is - # sorted in scope order. Typically there will be one item (of global scope) - # in the list. - #
    -- New in version 0.6.0 - name_map = {} - - def __init__(self): - self._sheet_list = [] - self._sheet_names = [] - self._sheet_visibility = [] # from BOUNDSHEET record - self.nsheets = 0 - self._sh_abs_posn = [] # sheet's absolute position in the stream - self._sharedstrings = [] - self._rich_text_runlist_map = {} - self.raw_user_name = False - self._sheethdr_count = 0 # BIFF 4W only - self.builtinfmtcount = -1 # unknown as yet. BIFF 3, 4S, 4W - self.initialise_format_info() - self._all_sheets_count = 0 # includes macro & VBA sheets - self._supbook_count = 0 - self._supbook_locals_inx = None - self._supbook_addins_inx = None - self._all_sheets_map = [] # maps an all_sheets index to a calc-sheets index (or -1) - self._externsheet_info = [] - self._externsheet_type_b57 = [] - self._extnsht_name_from_num = {} - self._sheet_num_from_name = {} - self._extnsht_count = 0 - self._supbook_types = [] - self._resources_released = 0 - self.addin_func_names = [] - self.name_obj_list = [] - self.colour_map = {} - self.palette_record = [] - self.xf_list = [] - self.style_name_map = {} - self.mem = b'' - self.filestr = b'' - - def biff2_8_load(self, filename=None, file_contents=None, - logfile=sys.stdout, verbosity=0, use_mmap=USE_MMAP, - encoding_override=None, - formatting_info=False, - on_demand=False, - ragged_rows=False, - ): - # DEBUG = 0 - self.logfile = logfile - self.verbosity = verbosity - self.use_mmap = use_mmap and MMAP_AVAILABLE - self.encoding_override = encoding_override - self.formatting_info = formatting_info - self.on_demand = on_demand - self.ragged_rows = ragged_rows - - if not file_contents: - with open(filename, "rb") as f: - f.seek(0, 2) # EOF - size = f.tell() - f.seek(0, 0) # BOF - if size == 0: - raise XLRDError("File size is 0 bytes") - if self.use_mmap: - self.filestr = mmap.mmap(f.fileno(), size, access=mmap.ACCESS_READ) - self.stream_len = size - else: - self.filestr = f.read() - self.stream_len = len(self.filestr) - else: - self.filestr = file_contents - self.stream_len = len(file_contents) - - self.base = 0 - if self.filestr[:8] != compdoc.SIGNATURE: - # got this one at the antique store - self.mem = self.filestr - else: - cd = compdoc.CompDoc(self.filestr, logfile=self.logfile) - if USE_FANCY_CD: - for qname in ['Workbook', 'Book']: - self.mem, self.base, self.stream_len = \ - cd.locate_named_stream(UNICODE_LITERAL(qname)) - if self.mem: break - else: - raise XLRDError("Can't find workbook in OLE2 compound document") - else: - for qname in ['Workbook', 'Book']: - self.mem = cd.get_named_stream(UNICODE_LITERAL(qname)) - if self.mem: break - else: - raise XLRDError("Can't find workbook in OLE2 compound document") - self.stream_len = len(self.mem) - del cd - if self.mem is not self.filestr: - if hasattr(self.filestr, "close"): - self.filestr.close() - self.filestr = b'' - self._position = self.base - if DEBUG: - print("mem: %s, base: %d, len: %d" % (type(self.mem), self.base, self.stream_len), file=self.logfile) - - def initialise_format_info(self): - # needs to be done once per sheet for BIFF 4W :-( - self.format_map = {} - self.format_list = [] - self.xfcount = 0 - self.actualfmtcount = 0 # number of FORMAT records seen so far - self._xf_index_to_xl_type_map = {0: XL_CELL_NUMBER} - self._xf_epilogue_done = 0 - self.xf_list = [] - self.font_list = [] - - def get2bytes(self): - pos = self._position - buff_two = self.mem[pos:pos+2] - lenbuff = len(buff_two) - self._position += lenbuff - if lenbuff < 2: - return MY_EOF - lo, hi = buff_two - return (BYTES_ORD(hi) << 8) | BYTES_ORD(lo) - - def get_record_parts(self): - pos = self._position - mem = self.mem - code, length = unpack('= 2: - fprintf(self.logfile, - "BOUNDSHEET: inx=%d vis=%r sheet_name=%r abs_posn=%d sheet_type=0x%02x\n", - self._all_sheets_count, visibility, sheet_name, abs_posn, sheet_type) - self._all_sheets_count += 1 - if sheet_type != XL_BOUNDSHEET_WORKSHEET: - self._all_sheets_map.append(-1) - descr = { - 1: 'Macro sheet', - 2: 'Chart', - 6: 'Visual Basic module', - }.get(sheet_type, 'UNKNOWN') - - if DEBUG or self.verbosity >= 1: - fprintf(self.logfile, - "NOTE *** Ignoring non-worksheet data named %r (type 0x%02x = %s)\n", - sheet_name, sheet_type, descr) - else: - snum = len(self._sheet_names) - self._all_sheets_map.append(snum) - self._sheet_names.append(sheet_name) - self._sh_abs_posn.append(abs_posn) - self._sheet_visibility.append(visibility) - self._sheet_num_from_name[sheet_name] = snum - - def handle_builtinfmtcount(self, data): - ### N.B. This count appears to be utterly useless. - # DEBUG = 1 - builtinfmtcount = unpack('= 2: - fprintf(self.logfile, "*** No CODEPAGE record; assuming 1200 (utf_16_le)\n") - else: - codepage = self.codepage - if codepage in encoding_from_codepage: - encoding = encoding_from_codepage[codepage] - elif 300 <= codepage <= 1999: - encoding = 'cp' + str(codepage) - else: - encoding = 'unknown_codepage_' + str(codepage) - if DEBUG or (self.verbosity and encoding != self.encoding) : - fprintf(self.logfile, "CODEPAGE: codepage %r -> encoding %r\n", codepage, encoding) - self.encoding = encoding - if self.codepage != 1200: # utf_16_le - # If we don't have a codec that can decode ASCII into Unicode, - # we're well & truly stuffed -- let the punter know ASAP. - try: - _unused = unicode(b'trial', self.encoding) - except BaseException as e: - fprintf(self.logfile, - "ERROR *** codepage %r -> encoding %r -> %s: %s\n", - self.codepage, self.encoding, type(e).__name__.split(".")[-1], e) - raise - if self.raw_user_name: - strg = unpack_string(self.user_name, 0, self.encoding, lenlen=1) - strg = strg.rstrip() - # if DEBUG: - # print "CODEPAGE: user name decoded from %r to %r" % (self.user_name, strg) - self.user_name = strg - self.raw_user_name = False - return self.encoding - - def handle_codepage(self, data): - # DEBUG = 0 - codepage = unpack('= 2 - if self.biff_version >= 80: - option_flags, other_info =unpack("= 1 - blah2 = DEBUG or self.verbosity >= 2 - if self.biff_version >= 80: - num_refs = unpack("= 2: - logf = self.logfile - fprintf(logf, "FILEPASS:\n") - hex_char_dump(data, 0, len(data), base=0, fout=logf) - if self.biff_version >= 80: - kind1, = unpack('= 2 - bv = self.biff_version - if bv < 50: - return - self.derive_encoding() - # print - # hex_char_dump(data, 0, len(data), fout=self.logfile) - ( - option_flags, kb_shortcut, name_len, fmla_len, extsht_index, sheet_index, - menu_text_len, description_text_len, help_topic_text_len, status_bar_text_len, - ) = unpack("> nshift) - - macro_flag = " M"[nobj.macro] - if bv < 80: - internal_name, pos = unpack_string_update_pos(data, 14, self.encoding, known_len=name_len) - else: - internal_name, pos = unpack_unicode_update_pos(data, 14, known_len=name_len) - nobj.extn_sheet_num = extsht_index - nobj.excel_sheet_index = sheet_index - nobj.scope = None # patched up in the names_epilogue() method - if blah: - fprintf( - self.logfile, - "NAME[%d]:%s oflags=%d, name_len=%d, fmla_len=%d, extsht_index=%d, sheet_index=%d, name=%r\n", - name_index, macro_flag, option_flags, name_len, - fmla_len, extsht_index, sheet_index, internal_name) - name = internal_name - if nobj.builtin: - name = builtin_name_from_code.get(name, "??Unknown??") - if blah: print(" builtin: %s" % name, file=self.logfile) - nobj.name = name - nobj.raw_formula = data[pos:] - nobj.basic_formula_len = fmla_len - nobj.evaluated = 0 - if blah: - nobj.dump( - self.logfile, - header="--- handle_name: name[%d] ---" % name_index, - footer="-------------------", - ) - - def names_epilogue(self): - blah = self.verbosity >= 2 - f = self.logfile - if blah: - print("+++++ names_epilogue +++++", file=f) - print("_all_sheets_map", REPR(self._all_sheets_map), file=f) - print("_extnsht_name_from_num", REPR(self._extnsht_name_from_num), file=f) - print("_sheet_num_from_name", REPR(self._sheet_num_from_name), file=f) - num_names = len(self.name_obj_list) - for namex in range(num_names): - nobj = self.name_obj_list[namex] - # Convert from excel_sheet_index to scope. - # This is done here because in BIFF7 and earlier, the - # BOUNDSHEET records (from which _all_sheets_map is derived) - # come after the NAME records. - if self.biff_version >= 80: - sheet_index = nobj.excel_sheet_index - if sheet_index == 0: - intl_sheet_index = -1 # global - elif 1 <= sheet_index <= len(self._all_sheets_map): - intl_sheet_index = self._all_sheets_map[sheet_index-1] - if intl_sheet_index == -1: # maps to a macro or VBA sheet - intl_sheet_index = -2 # valid sheet reference but not useful - else: - # huh? - intl_sheet_index = -3 # invalid - elif 50 <= self.biff_version <= 70: - sheet_index = nobj.extn_sheet_num - if sheet_index == 0: - intl_sheet_index = -1 # global - else: - sheet_name = self._extnsht_name_from_num[sheet_index] - intl_sheet_index = self._sheet_num_from_name.get(sheet_name, -2) - nobj.scope = intl_sheet_index - - for namex in range(num_names): - nobj = self.name_obj_list[namex] - # Parse the formula ... - if nobj.macro or nobj.binary: continue - if nobj.evaluated: continue - evaluate_name_formula(self, nobj, namex, blah=blah) - - if self.verbosity >= 2: - print("---------- name object dump ----------", file=f) - for namex in range(num_names): - nobj = self.name_obj_list[namex] - nobj.dump(f, header="--- name[%d] ---" % namex) - print("--------------------------------------", file=f) - # - # Build some dicts for access to the name objects - # - name_and_scope_map = {} # (name.lower(), scope): Name_object - name_map = {} # name.lower() : list of Name_objects (sorted in scope order) - for namex in range(num_names): - nobj = self.name_obj_list[namex] - name_lcase = nobj.name.lower() - key = (name_lcase, nobj.scope) - if key in name_and_scope_map and self.verbosity: - fprintf(f, 'Duplicate entry %r in name_and_scope_map\n', key) - name_and_scope_map[key] = nobj - sort_data = (nobj.scope, namex, nobj) - # namex (a temp unique ID) ensures the Name objects will not - # be compared (fatal in py3) - if name_lcase in name_map: - name_map[name_lcase].append(sort_data) - else: - name_map[name_lcase] = [sort_data] - for key in name_map.keys(): - alist = name_map[key] - alist.sort() - name_map[key] = [x[2] for x in alist] - self.name_and_scope_map = name_and_scope_map - self.name_map = name_map - - def handle_obj(self, data): - # Not doing much handling at all. - # Worrying about embedded (BOF ... EOF) substreams is done elsewhere. - # DEBUG = 1 - obj_type, obj_id = unpack(' handle_obj type=%d id=0x%08x" % (obj_type, obj_id) - - def handle_supbook(self, data): - # aka EXTERNALBOOK in OOo docs - self._supbook_types.append(None) - blah = DEBUG or self.verbosity >= 2 - if blah: - print("SUPBOOK:", file=self.logfile) - hex_char_dump(data, 0, len(data), fout=self.logfile) - num_sheets = unpack("= 2: - fprintf(self.logfile, "SST: unique strings: %d\n", uniquestrings) - while 1: - code, nb, data = self.get_record_parts_conditional(XL_CONTINUE) - if code is None: - break - nbt += nb - if DEBUG >= 2: - fprintf(self.logfile, "CONTINUE: adding %d bytes to SST -> %d\n", nb, nbt) - strlist.append(data) - self._sharedstrings, rt_runlist = unpack_SST_table(strlist, uniquestrings) - if self.formatting_info: - self._rich_text_runlist_map = rt_runlist - if DEBUG: - t1 = time.time() - print("SST processing took %.2f seconds" % (t1 - t0, ), file=self.logfile) - - def handle_writeaccess(self, data): - DEBUG = 0 - if self.biff_version < 80: - if not self.encoding: - self.raw_user_name = True - self.user_name = data - return - strg = unpack_string(data, 0, self.encoding, lenlen=1) - else: - strg = unpack_unicode(data, 0, lenlen=2) - if DEBUG: fprintf(self.logfile, "WRITEACCESS: %d bytes; raw=%s %r\n", len(data), self.raw_user_name, strg) - strg = strg.rstrip() - self.user_name = strg - - def parse_globals(self): - # DEBUG = 0 - # no need to position, just start reading (after the BOF) - formatting.initialise_book(self) - while 1: - rc, length, data = self.get_record_parts() - if DEBUG: print("parse_globals: record code is 0x%04x" % rc, file=self.logfile) - if rc == XL_SST: - self.handle_sst(data) - elif rc == XL_FONT or rc == XL_FONT_B3B4: - self.handle_font(data) - elif rc == XL_FORMAT: # XL_FORMAT2 is BIFF <= 3.0, can't appear in globals - self.handle_format(data) - elif rc == XL_XF: - self.handle_xf(data) - elif rc == XL_BOUNDSHEET: - self.handle_boundsheet(data) - elif rc == XL_DATEMODE: - self.handle_datemode(data) - elif rc == XL_CODEPAGE: - self.handle_codepage(data) - elif rc == XL_COUNTRY: - self.handle_country(data) - elif rc == XL_EXTERNNAME: - self.handle_externname(data) - elif rc == XL_EXTERNSHEET: - self.handle_externsheet(data) - elif rc == XL_FILEPASS: - self.handle_filepass(data) - elif rc == XL_WRITEACCESS: - self.handle_writeaccess(data) - elif rc == XL_SHEETSOFFSET: - self.handle_sheetsoffset(data) - elif rc == XL_SHEETHDR: - self.handle_sheethdr(data) - elif rc == XL_SUPBOOK: - self.handle_supbook(data) - elif rc == XL_NAME: - self.handle_name(data) - elif rc == XL_PALETTE: - self.handle_palette(data) - elif rc == XL_STYLE: - self.handle_style(data) - elif rc & 0xff == 9 and self.verbosity: - fprintf(self.logfile, "*** Unexpected BOF at posn %d: 0x%04x len=%d data=%r\n", - self._position - length - 4, rc, length, data) - elif rc == XL_EOF: - self.xf_epilogue() - self.names_epilogue() - self.palette_epilogue() - if not self.encoding: - self.derive_encoding() - if self.biff_version == 45: - # DEBUG = 0 - if DEBUG: print("global EOF: position", self._position, file=self.logfile) - # if DEBUG: - # pos = self._position - 4 - # print repr(self.mem[pos:pos+40]) - return - else: - # if DEBUG: - # print >> self.logfile, "parse_globals: ignoring record code 0x%04x" % rc - pass - - def read(self, pos, length): - data = self.mem[pos:pos+length] - self._position = pos + len(data) - return data - - def getbof(self, rqd_stream): - # DEBUG = 1 - # if DEBUG: print >> self.logfile, "getbof(): position", self._position - if DEBUG: print("reqd: 0x%04x" % rqd_stream, file=self.logfile) - def bof_error(msg): - raise XLRDError('Unsupported format, or corrupt file: ' + msg) - savpos = self._position - opcode = self.get2bytes() - if opcode == MY_EOF: - bof_error('Expected BOF record; met end of file') - if opcode not in bofcodes: - bof_error('Expected BOF record; found %r' % self.mem[savpos:savpos+8]) - length = self.get2bytes() - if length == MY_EOF: - bof_error('Incomplete BOF record[1]; met end of file') - if not (4 <= length <= 20): - bof_error( - 'Invalid length (%d) for BOF record type 0x%04x' - % (length, opcode)) - padding = b'\0' * max(0, boflen[opcode] - length) - data = self.read(self._position, length); - if DEBUG: fprintf(self.logfile, "\ngetbof(): data=%r\n", data) - if len(data) < length: - bof_error('Incomplete BOF record[2]; met end of file') - data += padding - version1 = opcode >> 8 - version2, streamtype = unpack('= 2: - print("BOF: op=0x%04x vers=0x%04x stream=0x%04x buildid=%d buildyr=%d -> BIFF%d" \ - % (opcode, version2, streamtype, build, year, version), file=self.logfile) - got_globals = streamtype == XL_WORKBOOK_GLOBALS or ( - version == 45 and streamtype == XL_WORKBOOK_GLOBALS_4W) - if (rqd_stream == XL_WORKBOOK_GLOBALS and got_globals) or streamtype == rqd_stream: - return version - if version < 50 and streamtype == XL_WORKSHEET: - return version - if version >= 50 and streamtype == 0x0100: - bof_error("Workspace file -- no spreadsheet data") - bof_error( - 'BOF not workbook/worksheet: op=0x%04x vers=0x%04x strm=0x%04x build=%d year=%d -> BIFF%d' \ - % (opcode, version2, streamtype, build, year, version) - ) - -# === helper functions - -def expand_cell_address(inrow, incol): - # Ref : OOo docs, "4.3.4 Cell Addresses in BIFF8" - outrow = inrow - if incol & 0x8000: - if outrow >= 32768: - outrow -= 65536 - relrow = 1 - else: - relrow = 0 - outcol = incol & 0xFF - if incol & 0x4000: - if outcol >= 128: - outcol -= 256 - relcol = 1 - else: - relcol = 0 - return outrow, outcol, relrow, relcol - -def colname(colx, _A2Z="ABCDEFGHIJKLMNOPQRSTUVWXYZ"): - assert colx >= 0 - name = UNICODE_LITERAL('') - while 1: - quot, rem = divmod(colx, 26) - name = _A2Z[rem] + name - if not quot: - return name - colx = quot - 1 - -def display_cell_address(rowx, colx, relrow, relcol): - if relrow: - rowpart = "(*%s%d)" % ("+-"[rowx < 0], abs(rowx)) - else: - rowpart = "$%d" % (rowx+1,) - if relcol: - colpart = "(*%s%d)" % ("+-"[colx < 0], abs(colx)) - else: - colpart = "$" + colname(colx) - return colpart + rowpart - -def unpack_SST_table(datatab, nstrings): - "Return list of strings" - datainx = 0 - ndatas = len(datatab) - data = datatab[0] - datalen = len(data) - pos = 8 - strings = [] - strappend = strings.append - richtext_runs = {} - local_unpack = unpack - local_min = min - local_BYTES_ORD = BYTES_ORD - latin_1 = "latin_1" - for _unused_i in xrange(nstrings): - nchars = local_unpack('> 1, charsneed) - rawstrg = data[pos:pos+2*charsavail] - # if DEBUG: print "SST U16: nchars=%d pos=%d rawstrg=%r" % (nchars, pos, rawstrg) - try: - accstrg += unicode(rawstrg, "utf_16_le") - except: - # print "SST U16: nchars=%d pos=%d rawstrg=%r" % (nchars, pos, rawstrg) - # Probable cause: dodgy data e.g. unfinished surrogate pair. - # E.g. file unicode2.xls in pyExcelerator's examples has cells containing - # unichr(i) for i in range(0x100000) - # so this will include 0xD800 etc - raise - pos += 2*charsavail - else: - # Note: this is COMPRESSED (not ASCII!) encoding!!! - charsavail = local_min(datalen - pos, charsneed) - rawstrg = data[pos:pos+charsavail] - # if DEBUG: print "SST CMPRSD: nchars=%d pos=%d rawstrg=%r" % (nchars, pos, rawstrg) - accstrg += unicode(rawstrg, latin_1) - pos += charsavail - charsgot += charsavail - if charsgot == nchars: - break - datainx += 1 - data = datatab[datainx] - datalen = len(data) - options = local_BYTES_ORD(data[0]) - pos = 1 - - if rtcount: - runs = [] - for runindex in xrange(rtcount): - if pos == datalen: - pos = 0 - datainx += 1 - data = datatab[datainx] - datalen = len(data) - runs.append(local_unpack("= datalen: - # adjust to correct position in next record - pos = pos - datalen - datainx += 1 - if datainx < ndatas: - data = datatab[datainx] - datalen = len(data) - else: - assert _unused_i == nstrings - 1 - strappend(accstrg) - return strings, richtext_runs diff --git a/webhub/xlrd/book.pyc b/webhub/xlrd/book.pyc deleted file mode 100644 index bf220c98..00000000 Binary files a/webhub/xlrd/book.pyc and /dev/null differ diff --git a/webhub/xlrd/compdoc.py b/webhub/xlrd/compdoc.py deleted file mode 100644 index e434e8ec..00000000 --- a/webhub/xlrd/compdoc.py +++ /dev/null @@ -1,473 +0,0 @@ -# -*- coding: cp1252 -*- - -## -# Implements the minimal functionality required -# to extract a "Workbook" or "Book" stream (as one big string) -# from an OLE2 Compound Document file. -#

    Copyright � 2005-2012 Stephen John Machin, Lingfo Pty Ltd

    -#

    This module is part of the xlrd package, which is released under a BSD-style licence.

    -## - -# No part of the content of this file was derived from the works of David Giffin. - -# 2008-11-04 SJM Avoid assertion error when -1 used instead of -2 for first_SID of empty SCSS [Frank Hoffsuemmer] -# 2007-09-08 SJM Warning message if sector sizes are extremely large. -# 2007-05-07 SJM Meaningful exception instead of IndexError if a SAT (sector allocation table) is corrupted. -# 2007-04-22 SJM Missing "<" in a struct.unpack call => can't open files on bigendian platforms. - -from __future__ import print_function -import sys -from struct import unpack -from .timemachine import * -import array - -## -# Magic cookie that should appear in the first 8 bytes of the file. -SIGNATURE = b"\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1" - -EOCSID = -2 -FREESID = -1 -SATSID = -3 -MSATSID = -4 -EVILSID = -5 - -class CompDocError(Exception): - pass - -class DirNode(object): - - def __init__(self, DID, dent, DEBUG=0, logfile=sys.stdout): - # dent is the 128-byte directory entry - self.DID = DID - self.logfile = logfile - (cbufsize, self.etype, self.colour, self.left_DID, self.right_DID, - self.root_DID) = \ - unpack(' 20: # allows for 2**20 bytes i.e. 1MB - print("WARNING: sector size (2**%d) is preposterous; assuming 512 and continuing ..." \ - % ssz, file=logfile) - ssz = 9 - if sssz > ssz: - print("WARNING: short stream sector size (2**%d) is preposterous; assuming 64 and continuing ..." \ - % sssz, file=logfile) - sssz = 6 - self.sec_size = sec_size = 1 << ssz - self.short_sec_size = 1 << sssz - if self.sec_size != 512 or self.short_sec_size != 64: - print("@@@@ sec_size=%d short_sec_size=%d" % (self.sec_size, self.short_sec_size), file=logfile) - ( - SAT_tot_secs, self.dir_first_sec_sid, _unused, self.min_size_std_stream, - SSAT_first_sec_sid, SSAT_tot_secs, - MSATX_first_sec_sid, MSATX_tot_secs, - # ) = unpack(' 1: - print('MSATX: sid=%d (0x%08X)' % (sid, sid), file=logfile) - if sid >= mem_data_secs: - msg = "MSAT extension: accessing sector %d but only %d in file" % (sid, mem_data_secs) - if DEBUG > 1: - print(msg, file=logfile) - break - raise CompDocError(msg) - elif sid < 0: - raise CompDocError("MSAT extension: invalid sector id: %d" % sid) - if seen[sid]: - raise CompDocError("MSAT corruption: seen[%d] == %d" % (sid, seen[sid])) - seen[sid] = 1 - actual_MSATX_sectors += 1 - if DEBUG and actual_MSATX_sectors > expected_MSATX_sectors: - print("[1]===>>>", mem_data_secs, nent, SAT_sectors_reqd, expected_MSATX_sectors, actual_MSATX_sectors, file=logfile) - offset = 512 + sec_size * sid - MSAT.extend(unpack(fmt, mem[offset:offset+sec_size])) - sid = MSAT.pop() # last sector id is sid of next sector in the chain - - if DEBUG and actual_MSATX_sectors != expected_MSATX_sectors: - print("[2]===>>>", mem_data_secs, nent, SAT_sectors_reqd, expected_MSATX_sectors, actual_MSATX_sectors, file=logfile) - if DEBUG: - print("MSAT: len =", len(MSAT), file=logfile) - dump_list(MSAT, 10, logfile) - # - # === build the SAT === - # - self.SAT = [] - actual_SAT_sectors = 0 - dump_again = 0 - for msidx in xrange(len(MSAT)): - msid = MSAT[msidx] - if msid in (FREESID, EOCSID): - # Specification: the MSAT array may be padded with trailing FREESID entries. - # Toleration: a FREESID or EOCSID entry anywhere in the MSAT array will be ignored. - continue - if msid >= mem_data_secs: - if not trunc_warned: - print("WARNING *** File is truncated, or OLE2 MSAT is corrupt!!", file=logfile) - print("INFO: Trying to access sector %d but only %d available" \ - % (msid, mem_data_secs), file=logfile) - trunc_warned = 1 - MSAT[msidx] = EVILSID - dump_again = 1 - continue - elif msid < -2: - raise CompDocError("MSAT: invalid sector id: %d" % msid) - if seen[msid]: - raise CompDocError("MSAT extension corruption: seen[%d] == %d" % (msid, seen[msid])) - seen[msid] = 2 - actual_SAT_sectors += 1 - if DEBUG and actual_SAT_sectors > SAT_sectors_reqd: - print("[3]===>>>", mem_data_secs, nent, SAT_sectors_reqd, expected_MSATX_sectors, actual_MSATX_sectors, actual_SAT_sectors, msid, file=logfile) - offset = 512 + sec_size * msid - self.SAT.extend(unpack(fmt, mem[offset:offset+sec_size])) - - if DEBUG: - print("SAT: len =", len(self.SAT), file=logfile) - dump_list(self.SAT, 10, logfile) - # print >> logfile, "SAT ", - # for i, s in enumerate(self.SAT): - # print >> logfile, "entry: %4d offset: %6d, next entry: %4d" % (i, 512 + sec_size * i, s) - # print >> logfile, "%d:%d " % (i, s), - print(file=logfile) - if DEBUG and dump_again: - print("MSAT: len =", len(MSAT), file=logfile) - dump_list(MSAT, 10, logfile) - for satx in xrange(mem_data_secs, len(self.SAT)): - self.SAT[satx] = EVILSID - print("SAT: len =", len(self.SAT), file=logfile) - dump_list(self.SAT, 10, logfile) - # - # === build the directory === - # - dbytes = self._get_stream( - self.mem, 512, self.SAT, self.sec_size, self.dir_first_sec_sid, - name="directory", seen_id=3) - dirlist = [] - did = -1 - for pos in xrange(0, len(dbytes), 128): - did += 1 - dirlist.append(DirNode(did, dbytes[pos:pos+128], 0, logfile)) - self.dirlist = dirlist - _build_family_tree(dirlist, 0, dirlist[0].root_DID) # and stand well back ... - if DEBUG: - for d in dirlist: - d.dump(DEBUG) - # - # === get the SSCS === - # - sscs_dir = self.dirlist[0] - assert sscs_dir.etype == 5 # root entry - if sscs_dir.first_SID < 0 or sscs_dir.tot_size == 0: - # Problem reported by Frank Hoffsuemmer: some software was - # writing -1 instead of -2 (EOCSID) for the first_SID - # when the SCCS was empty. Not having EOCSID caused assertion - # failure in _get_stream. - # Solution: avoid calling _get_stream in any case when the - # SCSS appears to be empty. - self.SSCS = "" - else: - self.SSCS = self._get_stream( - self.mem, 512, self.SAT, sec_size, sscs_dir.first_SID, - sscs_dir.tot_size, name="SSCS", seen_id=4) - # if DEBUG: print >> logfile, "SSCS", repr(self.SSCS) - # - # === build the SSAT === - # - self.SSAT = [] - if SSAT_tot_secs > 0 and sscs_dir.tot_size == 0: - print("WARNING *** OLE2 inconsistency: SSCS size is 0 but SSAT size is non-zero", file=logfile) - if sscs_dir.tot_size > 0: - sid = SSAT_first_sec_sid - nsecs = SSAT_tot_secs - while sid >= 0 and nsecs > 0: - if seen[sid]: - raise CompDocError("SSAT corruption: seen[%d] == %d" % (sid, seen[sid])) - seen[sid] = 5 - nsecs -= 1 - start_pos = 512 + sid * sec_size - news = list(unpack(fmt, mem[start_pos:start_pos+sec_size])) - self.SSAT.extend(news) - sid = self.SAT[sid] - if DEBUG: print("SSAT last sid %d; remaining sectors %d" % (sid, nsecs), file=logfile) - assert nsecs == 0 and sid == EOCSID - if DEBUG: - print("SSAT", file=logfile) - dump_list(self.SSAT, 10, logfile) - if DEBUG: - print("seen", file=logfile) - dump_list(seen, 20, logfile) - - def _get_stream(self, mem, base, sat, sec_size, start_sid, size=None, name='', seen_id=None): - # print >> self.logfile, "_get_stream", base, sec_size, start_sid, size - sectors = [] - s = start_sid - if size is None: - # nothing to check against - while s >= 0: - if seen_id is not None: - if self.seen[s]: - raise CompDocError("%s corruption: seen[%d] == %d" % (name, s, self.seen[s])) - self.seen[s] = seen_id - start_pos = base + s * sec_size - sectors.append(mem[start_pos:start_pos+sec_size]) - try: - s = sat[s] - except IndexError: - raise CompDocError( - "OLE2 stream %r: sector allocation table invalid entry (%d)" % - (name, s) - ) - assert s == EOCSID - else: - todo = size - while s >= 0: - if seen_id is not None: - if self.seen[s]: - raise CompDocError("%s corruption: seen[%d] == %d" % (name, s, self.seen[s])) - self.seen[s] = seen_id - start_pos = base + s * sec_size - grab = sec_size - if grab > todo: - grab = todo - todo -= grab - sectors.append(mem[start_pos:start_pos+grab]) - try: - s = sat[s] - except IndexError: - raise CompDocError( - "OLE2 stream %r: sector allocation table invalid entry (%d)" % - (name, s) - ) - assert s == EOCSID - if todo != 0: - fprintf(self.logfile, - "WARNING *** OLE2 stream %r: expected size %d, actual size %d\n", - name, size, size - todo) - - return b''.join(sectors) - - def _dir_search(self, path, storage_DID=0): - # Return matching DirNode instance, or None - head = path[0] - tail = path[1:] - dl = self.dirlist - for child in dl[storage_DID].children: - if dl[child].name.lower() == head.lower(): - et = dl[child].etype - if et == 2: - return dl[child] - if et == 1: - if not tail: - raise CompDocError("Requested component is a 'storage'") - return self._dir_search(tail, child) - dl[child].dump(1) - raise CompDocError("Requested stream is not a 'user stream'") - return None - - ## - # Interrogate the compound document's directory; return the stream as a string if found, otherwise - # return None. - # @param qname Name of the desired stream e.g. u'Workbook'. Should be in Unicode or convertible thereto. - - def get_named_stream(self, qname): - d = self._dir_search(qname.split("/")) - if d is None: - return None - if d.tot_size >= self.min_size_std_stream: - return self._get_stream( - self.mem, 512, self.SAT, self.sec_size, d.first_SID, - d.tot_size, name=qname, seen_id=d.DID+6) - else: - return self._get_stream( - self.SSCS, 0, self.SSAT, self.short_sec_size, d.first_SID, - d.tot_size, name=qname + " (from SSCS)", seen_id=None) - - ## - # Interrogate the compound document's directory. - # If the named stream is not found, (None, 0, 0) will be returned. - # If the named stream is found and is contiguous within the original byte sequence ("mem") - # used when the document was opened, - # then (mem, offset_to_start_of_stream, length_of_stream) is returned. - # Otherwise a new string is built from the fragments and (new_string, 0, length_of_stream) is returned. - # @param qname Name of the desired stream e.g. u'Workbook'. Should be in Unicode or convertible thereto. - - def locate_named_stream(self, qname): - d = self._dir_search(qname.split("/")) - if d is None: - return (None, 0, 0) - if d.tot_size > self.mem_data_len: - raise CompDocError("%r stream length (%d bytes) > file data size (%d bytes)" - % (qname, d.tot_size, self.mem_data_len)) - if d.tot_size >= self.min_size_std_stream: - result = self._locate_stream( - self.mem, 512, self.SAT, self.sec_size, d.first_SID, - d.tot_size, qname, d.DID+6) - if self.DEBUG: - print("\nseen", file=self.logfile) - dump_list(self.seen, 20, self.logfile) - return result - else: - return ( - self._get_stream( - self.SSCS, 0, self.SSAT, self.short_sec_size, d.first_SID, - d.tot_size, qname + " (from SSCS)", None), - 0, - d.tot_size - ) - - def _locate_stream(self, mem, base, sat, sec_size, start_sid, expected_stream_size, qname, seen_id): - # print >> self.logfile, "_locate_stream", base, sec_size, start_sid, expected_stream_size - s = start_sid - if s < 0: - raise CompDocError("_locate_stream: start_sid (%d) is -ve" % start_sid) - p = -99 # dummy previous SID - start_pos = -9999 - end_pos = -8888 - slices = [] - tot_found = 0 - found_limit = (expected_stream_size + sec_size - 1) // sec_size - while s >= 0: - if self.seen[s]: - print("_locate_stream(%s): seen" % qname, file=self.logfile); dump_list(self.seen, 20, self.logfile) - raise CompDocError("%s corruption: seen[%d] == %d" % (qname, s, self.seen[s])) - self.seen[s] = seen_id - tot_found += 1 - if tot_found > found_limit: - raise CompDocError( - "%s: size exceeds expected %d bytes; corrupt?" - % (qname, found_limit * sec_size) - ) # Note: expected size rounded up to higher sector - if s == p+1: - # contiguous sectors - end_pos += sec_size - else: - # start new slice - if p >= 0: - # not first time - slices.append((start_pos, end_pos)) - start_pos = base + s * sec_size - end_pos = start_pos + sec_size - p = s - s = sat[s] - assert s == EOCSID - assert tot_found == found_limit - # print >> self.logfile, "_locate_stream(%s): seen" % qname; dump_list(self.seen, 20, self.logfile) - if not slices: - # The stream is contiguous ... just what we like! - return (mem, start_pos, expected_stream_size) - slices.append((start_pos, end_pos)) - # print >> self.logfile, "+++>>> %d fragments" % len(slices) - return (b''.join([mem[start_pos:end_pos] for start_pos, end_pos in slices]), 0, expected_stream_size) - -# ========================================================================================== -def x_dump_line(alist, stride, f, dpos, equal=0): - print("%5d%s" % (dpos, " ="[equal]), end=' ', file=f) - for value in alist[dpos:dpos + stride]: - print(str(value), end=' ', file=f) - print(file=f) - -def dump_list(alist, stride, f=sys.stdout): - def _dump_line(dpos, equal=0): - print("%5d%s" % (dpos, " ="[equal]), end=' ', file=f) - for value in alist[dpos:dpos + stride]: - print(str(value), end=' ', file=f) - print(file=f) - pos = None - oldpos = None - for pos in xrange(0, len(alist), stride): - if oldpos is None: - _dump_line(pos) - oldpos = pos - elif alist[pos:pos+stride] != alist[oldpos:oldpos+stride]: - if pos - oldpos > stride: - _dump_line(pos - stride, equal=1) - _dump_line(pos) - oldpos = pos - if oldpos is not None and pos is not None and pos != oldpos: - _dump_line(pos, equal=1) diff --git a/webhub/xlrd/compdoc.pyc b/webhub/xlrd/compdoc.pyc deleted file mode 100644 index 0949ae7c..00000000 Binary files a/webhub/xlrd/compdoc.pyc and /dev/null differ diff --git a/webhub/xlrd/formatting.py b/webhub/xlrd/formatting.py deleted file mode 100644 index f0449151..00000000 --- a/webhub/xlrd/formatting.py +++ /dev/null @@ -1,1262 +0,0 @@ -# -*- coding: cp1252 -*- - -## -# Module for formatting information. -# -#

    Copyright 2005-2012 Stephen John Machin, Lingfo Pty Ltd

    -#

    This module is part of the xlrd package, which is released under -# a BSD-style licence.

    -## - -# No part of the content of this file was derived from the works of David Giffin. - -from __future__ import print_function - -DEBUG = 0 -import re -from struct import unpack -from .timemachine import * -from .biffh import BaseObject, unpack_unicode, unpack_string, \ - upkbits, upkbitsL, fprintf, \ - FUN, FDT, FNU, FGE, FTX, XL_CELL_NUMBER, XL_CELL_DATE, \ - XL_FORMAT, XL_FORMAT2, \ - XLRDError - -_cellty_from_fmtty = { - FNU: XL_CELL_NUMBER, - FUN: XL_CELL_NUMBER, - FGE: XL_CELL_NUMBER, - FDT: XL_CELL_DATE, - FTX: XL_CELL_NUMBER, # Yes, a number can be formatted as text. - } - -excel_default_palette_b5 = ( - ( 0, 0, 0), (255, 255, 255), (255, 0, 0), ( 0, 255, 0), - ( 0, 0, 255), (255, 255, 0), (255, 0, 255), ( 0, 255, 255), - (128, 0, 0), ( 0, 128, 0), ( 0, 0, 128), (128, 128, 0), - (128, 0, 128), ( 0, 128, 128), (192, 192, 192), (128, 128, 128), - (153, 153, 255), (153, 51, 102), (255, 255, 204), (204, 255, 255), - (102, 0, 102), (255, 128, 128), ( 0, 102, 204), (204, 204, 255), - ( 0, 0, 128), (255, 0, 255), (255, 255, 0), ( 0, 255, 255), - (128, 0, 128), (128, 0, 0), ( 0, 128, 128), ( 0, 0, 255), - ( 0, 204, 255), (204, 255, 255), (204, 255, 204), (255, 255, 153), - (153, 204, 255), (255, 153, 204), (204, 153, 255), (227, 227, 227), - ( 51, 102, 255), ( 51, 204, 204), (153, 204, 0), (255, 204, 0), - (255, 153, 0), (255, 102, 0), (102, 102, 153), (150, 150, 150), - ( 0, 51, 102), ( 51, 153, 102), ( 0, 51, 0), ( 51, 51, 0), - (153, 51, 0), (153, 51, 102), ( 51, 51, 153), ( 51, 51, 51), - ) - -excel_default_palette_b2 = excel_default_palette_b5[:16] - -# Following table borrowed from Gnumeric 1.4 source. -# Checked against OOo docs and MS docs. -excel_default_palette_b8 = ( # (red, green, blue) - ( 0, 0, 0), (255,255,255), (255, 0, 0), ( 0,255, 0), # 0 - ( 0, 0,255), (255,255, 0), (255, 0,255), ( 0,255,255), # 4 - (128, 0, 0), ( 0,128, 0), ( 0, 0,128), (128,128, 0), # 8 - (128, 0,128), ( 0,128,128), (192,192,192), (128,128,128), # 12 - (153,153,255), (153, 51,102), (255,255,204), (204,255,255), # 16 - (102, 0,102), (255,128,128), ( 0,102,204), (204,204,255), # 20 - ( 0, 0,128), (255, 0,255), (255,255, 0), ( 0,255,255), # 24 - (128, 0,128), (128, 0, 0), ( 0,128,128), ( 0, 0,255), # 28 - ( 0,204,255), (204,255,255), (204,255,204), (255,255,153), # 32 - (153,204,255), (255,153,204), (204,153,255), (255,204,153), # 36 - ( 51,102,255), ( 51,204,204), (153,204, 0), (255,204, 0), # 40 - (255,153, 0), (255,102, 0), (102,102,153), (150,150,150), # 44 - ( 0, 51,102), ( 51,153,102), ( 0, 51, 0), ( 51, 51, 0), # 48 - (153, 51, 0), (153, 51,102), ( 51, 51,153), ( 51, 51, 51), # 52 - ) - -default_palette = { - 80: excel_default_palette_b8, - 70: excel_default_palette_b5, - 50: excel_default_palette_b5, - 45: excel_default_palette_b2, - 40: excel_default_palette_b2, - 30: excel_default_palette_b2, - 21: excel_default_palette_b2, - 20: excel_default_palette_b2, - } - -""" -00H = Normal -01H = RowLevel_lv (see next field) -02H = ColLevel_lv (see next field) -03H = Comma -04H = Currency -05H = Percent -06H = Comma [0] (BIFF4-BIFF8) -07H = Currency [0] (BIFF4-BIFF8) -08H = Hyperlink (BIFF8) -09H = Followed Hyperlink (BIFF8) -""" -built_in_style_names = [ - "Normal", - "RowLevel_", - "ColLevel_", - "Comma", - "Currency", - "Percent", - "Comma [0]", - "Currency [0]", - "Hyperlink", - "Followed Hyperlink", - ] - -def initialise_colour_map(book): - book.colour_map = {} - book.colour_indexes_used = {} - if not book.formatting_info: - return - # Add the 8 invariant colours - for i in xrange(8): - book.colour_map[i] = excel_default_palette_b8[i] - # Add the default palette depending on the version - dpal = default_palette[book.biff_version] - ndpal = len(dpal) - for i in xrange(ndpal): - book.colour_map[i+8] = dpal[i] - # Add the specials -- None means the RGB value is not known - # System window text colour for border lines - book.colour_map[ndpal+8] = None - # System window background colour for pattern background - book.colour_map[ndpal+8+1] = None # - for ci in ( - 0x51, # System ToolTip text colour (used in note objects) - 0x7FFF, # 32767, system window text colour for fonts - ): - book.colour_map[ci] = None - -def nearest_colour_index(colour_map, rgb, debug=0): - # General purpose function. Uses Euclidean distance. - # So far used only for pre-BIFF8 WINDOW2 record. - # Doesn't have to be fast. - # Doesn't have to be fancy. - best_metric = 3 * 256 * 256 - best_colourx = 0 - for colourx, cand_rgb in colour_map.items(): - if cand_rgb is None: - continue - metric = 0 - for v1, v2 in zip(rgb, cand_rgb): - metric += (v1 - v2) * (v1 - v2) - if metric < best_metric: - best_metric = metric - best_colourx = colourx - if metric == 0: - break - if 0 and debug: - print("nearest_colour_index for %r is %r -> %r; best_metric is %d" \ - % (rgb, best_colourx, colour_map[best_colourx], best_metric)) - return best_colourx - -## -# This mixin class exists solely so that Format, Font, and XF.... objects -# can be compared by value of their attributes. -class EqNeAttrs(object): - - def __eq__(self, other): - return self.__dict__ == other.__dict__ - - def __ne__(self, other): - return self.__dict__ != other.__dict__ - -## -# An Excel "font" contains the details of not only what is normally -# considered a font, but also several other display attributes. -# Items correspond to those in the Excel UI's Format/Cells/Font tab. -#
    -- New in version 0.6.1 -class Font(BaseObject, EqNeAttrs): - ## - # 1 = Characters are bold. Redundant; see "weight" attribute. - bold = 0 - ## - # Values: 0 = ANSI Latin, 1 = System default, 2 = Symbol, - # 77 = Apple Roman, - # 128 = ANSI Japanese Shift-JIS, - # 129 = ANSI Korean (Hangul), - # 130 = ANSI Korean (Johab), - # 134 = ANSI Chinese Simplified GBK, - # 136 = ANSI Chinese Traditional BIG5, - # 161 = ANSI Greek, - # 162 = ANSI Turkish, - # 163 = ANSI Vietnamese, - # 177 = ANSI Hebrew, - # 178 = ANSI Arabic, - # 186 = ANSI Baltic, - # 204 = ANSI Cyrillic, - # 222 = ANSI Thai, - # 238 = ANSI Latin II (Central European), - # 255 = OEM Latin I - character_set = 0 - ## - # An explanation of "colour index" is given in the Formatting - # section at the start of this document. - colour_index = 0 - ## - # 1 = Superscript, 2 = Subscript. - escapement = 0 - ## - # 0 = None (unknown or don't care)
    - # 1 = Roman (variable width, serifed)
    - # 2 = Swiss (variable width, sans-serifed)
    - # 3 = Modern (fixed width, serifed or sans-serifed)
    - # 4 = Script (cursive)
    - # 5 = Decorative (specialised, for example Old English, Fraktur) - family = 0 - ## - # The 0-based index used to refer to this Font() instance. - # Note that index 4 is never used; xlrd supplies a dummy place-holder. - font_index = 0 - ## - # Height of the font (in twips). A twip = 1/20 of a point. - height = 0 - ## - # 1 = Characters are italic. - italic = 0 - ## - # The name of the font. Example: u"Arial" - name = UNICODE_LITERAL("") - ## - # 1 = Characters are struck out. - struck_out = 0 - ## - # 0 = None
    - # 1 = Single; 0x21 (33) = Single accounting
    - # 2 = Double; 0x22 (34) = Double accounting - underline_type = 0 - ## - # 1 = Characters are underlined. Redundant; see "underline_type" attribute. - underlined = 0 - ## - # Font weight (100-1000). Standard values are 400 for normal text - # and 700 for bold text. - weight = 400 - ## - # 1 = Font is outline style (Macintosh only) - outline = 0 - ## - # 1 = Font is shadow style (Macintosh only) - shadow = 0 - - # No methods ... - -def handle_efont(book, data): # BIFF2 only - if not book.formatting_info: - return - book.font_list[-1].colour_index = unpack('= 2 - bv = book.biff_version - k = len(book.font_list) - if k == 4: - f = Font() - f.name = UNICODE_LITERAL('Dummy Font') - f.font_index = k - book.font_list.append(f) - k += 1 - f = Font() - f.font_index = k - book.font_list.append(f) - if bv >= 50: - ( - f.height, option_flags, f.colour_index, f.weight, - f.escapement, f.underline_type, f.family, - f.character_set, - ) = unpack('> 1 - f.underlined = (option_flags & 4) >> 2 - f.struck_out = (option_flags & 8) >> 3 - f.outline = (option_flags & 16) >> 4 - f.shadow = (option_flags & 32) >> 5 - if bv >= 80: - f.name = unpack_unicode(data, 14, lenlen=1) - else: - f.name = unpack_string(data, 14, book.encoding, lenlen=1) - elif bv >= 30: - f.height, option_flags, f.colour_index = unpack('> 1 - f.underlined = (option_flags & 4) >> 2 - f.struck_out = (option_flags & 8) >> 3 - f.outline = (option_flags & 16) >> 4 - f.shadow = (option_flags & 32) >> 5 - f.name = unpack_string(data, 6, book.encoding, lenlen=1) - # Now cook up the remaining attributes ... - f.weight = [400, 700][f.bold] - f.escapement = 0 # None - f.underline_type = f.underlined # None or Single - f.family = 0 # Unknown / don't care - f.character_set = 1 # System default (0 means "ANSI Latin") - else: # BIFF2 - f.height, option_flags = unpack('> 1 - f.underlined = (option_flags & 4) >> 2 - f.struck_out = (option_flags & 8) >> 3 - f.outline = 0 - f.shadow = 0 - f.name = unpack_string(data, 4, book.encoding, lenlen=1) - # Now cook up the remaining attributes ... - f.weight = [400, 700][f.bold] - f.escapement = 0 # None - f.underline_type = f.underlined # None or Single - f.family = 0 # Unknown / don't care - f.character_set = 1 # System default (0 means "ANSI Latin") - if blah: - f.dump( - book.logfile, - header="--- handle_font: font[%d] ---" % f.font_index, - footer="-------------------", - ) - -# === "Number formats" === - -## -# "Number format" information from a FORMAT record. -#
    -- New in version 0.6.1 -class Format(BaseObject, EqNeAttrs): - ## - # The key into Book.format_map - format_key = 0 - ## - # A classification that has been inferred from the format string. - # Currently, this is used only to distinguish between numbers and dates. - #
    Values: - #
    FUN = 0 # unknown - #
    FDT = 1 # date - #
    FNU = 2 # number - #
    FGE = 3 # general - #
    FTX = 4 # text - type = FUN - ## - # The format string - format_str = UNICODE_LITERAL('') - - def __init__(self, format_key, ty, format_str): - self.format_key = format_key - self.type = ty - self.format_str = format_str - -std_format_strings = { - # "std" == "standard for US English locale" - # #### TODO ... a lot of work to tailor these to the user's locale. - # See e.g. gnumeric-1.x.y/src/formats.c - 0x00: "General", - 0x01: "0", - 0x02: "0.00", - 0x03: "#,##0", - 0x04: "#,##0.00", - 0x05: "$#,##0_);($#,##0)", - 0x06: "$#,##0_);[Red]($#,##0)", - 0x07: "$#,##0.00_);($#,##0.00)", - 0x08: "$#,##0.00_);[Red]($#,##0.00)", - 0x09: "0%", - 0x0a: "0.00%", - 0x0b: "0.00E+00", - 0x0c: "# ?/?", - 0x0d: "# ??/??", - 0x0e: "m/d/yy", - 0x0f: "d-mmm-yy", - 0x10: "d-mmm", - 0x11: "mmm-yy", - 0x12: "h:mm AM/PM", - 0x13: "h:mm:ss AM/PM", - 0x14: "h:mm", - 0x15: "h:mm:ss", - 0x16: "m/d/yy h:mm", - 0x25: "#,##0_);(#,##0)", - 0x26: "#,##0_);[Red](#,##0)", - 0x27: "#,##0.00_);(#,##0.00)", - 0x28: "#,##0.00_);[Red](#,##0.00)", - 0x29: "_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(@_)", - 0x2a: "_($* #,##0_);_($* (#,##0);_($* \"-\"_);_(@_)", - 0x2b: "_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)", - 0x2c: "_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(@_)", - 0x2d: "mm:ss", - 0x2e: "[h]:mm:ss", - 0x2f: "mm:ss.0", - 0x30: "##0.0E+0", - 0x31: "@", - } - -fmt_code_ranges = [ # both-inclusive ranges of "standard" format codes - # Source: the openoffice.org doc't - # and the OOXML spec Part 4, section 3.8.30 - ( 0, 0, FGE), - ( 1, 13, FNU), - (14, 22, FDT), - (27, 36, FDT), # CJK date formats - (37, 44, FNU), - (45, 47, FDT), - (48, 48, FNU), - (49, 49, FTX), - # Gnumeric assumes (or assumed) that built-in formats finish at 49, not at 163 - (50, 58, FDT), # CJK date formats - (59, 62, FNU), # Thai number (currency?) formats - (67, 70, FNU), # Thai number (currency?) formats - (71, 81, FDT), # Thai date formats - ] - -std_format_code_types = {} -for lo, hi, ty in fmt_code_ranges: - for x in xrange(lo, hi+1): - std_format_code_types[x] = ty -del lo, hi, ty, x - -date_chars = UNICODE_LITERAL('ymdhs') # year, month/minute, day, hour, second -date_char_dict = {} -for _c in date_chars + date_chars.upper(): - date_char_dict[_c] = 5 -del _c, date_chars - -skip_char_dict = {} -for _c in UNICODE_LITERAL('$-+/(): '): - skip_char_dict[_c] = 1 - -num_char_dict = { - UNICODE_LITERAL('0'): 5, - UNICODE_LITERAL('#'): 5, - UNICODE_LITERAL('?'): 5, - } - -non_date_formats = { - UNICODE_LITERAL('0.00E+00'):1, - UNICODE_LITERAL('##0.0E+0'):1, - UNICODE_LITERAL('General') :1, - UNICODE_LITERAL('GENERAL') :1, # OOo Calc 1.1.4 does this. - UNICODE_LITERAL('general') :1, # pyExcelerator 0.6.3 does this. - UNICODE_LITERAL('@') :1, - } - -fmt_bracketed_sub = re.compile(r'\[[^]]*\]').sub - -# Boolean format strings (actual cases) -# u'"Yes";"Yes";"No"' -# u'"True";"True";"False"' -# u'"On";"On";"Off"' - -def is_date_format_string(book, fmt): - # Heuristics: - # Ignore "text" and [stuff in square brackets (aarrgghh -- see below)]. - # Handle backslashed-escaped chars properly. - # E.g. hh\hmm\mss\s should produce a display like 23h59m59s - # Date formats have one or more of ymdhs (caseless) in them. - # Numeric formats have # and 0. - # N.B. u'General"."' hence get rid of "text" first. - # TODO: Find where formats are interpreted in Gnumeric - # TODO: u'[h]\\ \\h\\o\\u\\r\\s' ([h] means don't care about hours > 23) - state = 0 - s = '' - - for c in fmt: - if state == 0: - if c == UNICODE_LITERAL('"'): - state = 1 - elif c in UNICODE_LITERAL(r"\_*"): - state = 2 - elif c in skip_char_dict: - pass - else: - s += c - elif state == 1: - if c == UNICODE_LITERAL('"'): - state = 0 - elif state == 2: - # Ignore char after backslash, underscore or asterisk - state = 0 - assert 0 <= state <= 2 - if book.verbosity >= 4: - print("is_date_format_string: reduced format is %s" % REPR(s), file=book.logfile) - s = fmt_bracketed_sub('', s) - if s in non_date_formats: - return False - state = 0 - separator = ";" - got_sep = 0 - date_count = num_count = 0 - for c in s: - if c in date_char_dict: - date_count += date_char_dict[c] - elif c in num_char_dict: - num_count += num_char_dict[c] - elif c == separator: - got_sep = 1 - # print num_count, date_count, repr(fmt) - if date_count and not num_count: - return True - if num_count and not date_count: - return False - if date_count: - if book.verbosity: - fprintf(book.logfile, - 'WARNING *** is_date_format: ambiguous d=%d n=%d fmt=%r\n', - date_count, num_count, fmt) - elif not got_sep: - if book.verbosity: - fprintf(book.logfile, - "WARNING *** format %r produces constant result\n", - fmt) - return date_count > num_count - -def handle_format(self, data, rectype=XL_FORMAT): - DEBUG = 0 - bv = self.biff_version - if rectype == XL_FORMAT2: - bv = min(bv, 30) - if not self.encoding: - self.derive_encoding() - strpos = 2 - if bv >= 50: - fmtkey = unpack('= 80: - unistrg = unpack_unicode(data, 2) - else: - unistrg = unpack_string(data, strpos, self.encoding, lenlen=1) - blah = DEBUG or self.verbosity >= 3 - if blah: - fprintf(self.logfile, - "FORMAT: count=%d fmtkey=0x%04x (%d) s=%r\n", - self.actualfmtcount, fmtkey, fmtkey, unistrg) - is_date_s = self.is_date_format_string(unistrg) - ty = [FGE, FDT][is_date_s] - if not(fmtkey > 163 or bv < 50): - # user_defined if fmtkey > 163 - # N.B. Gnumeric incorrectly starts these at 50 instead of 164 :-( - # if earlier than BIFF 5, standard info is useless - std_ty = std_format_code_types.get(fmtkey, FUN) - # print "std ty", std_ty - is_date_c = std_ty == FDT - if self.verbosity and 0 < fmtkey < 50 and (is_date_c ^ is_date_s): - DEBUG = 2 - fprintf(self.logfile, - "WARNING *** Conflict between " - "std format key %d and its format string %r\n", - fmtkey, unistrg) - if DEBUG == 2: - fprintf(self.logfile, - "ty: %d; is_date_c: %r; is_date_s: %r; fmt_strg: %r", - ty, is_date_c, is_date_s, unistrg) - fmtobj = Format(fmtkey, ty, unistrg) - if blah: - fmtobj.dump(self.logfile, - header="--- handle_format [%d] ---" % (self.actualfmtcount-1, )) - self.format_map[fmtkey] = fmtobj - self.format_list.append(fmtobj) - -# ============================================================================= - -def handle_palette(book, data): - if not book.formatting_info: - return - blah = DEBUG or book.verbosity >= 2 - n_colours, = unpack('= 50] - if ((DEBUG or book.verbosity >= 1) - and n_colours != expected_n_colours): - fprintf(book.logfile, - "NOTE *** Expected %d colours in PALETTE record, found %d\n", - expected_n_colours, n_colours) - elif blah: - fprintf(book.logfile, - "PALETTE record with %d colours\n", n_colours) - fmt = '> 8) & 0xff - blue = (c >> 16) & 0xff - old_rgb = book.colour_map[8+i] - new_rgb = (red, green, blue) - book.palette_record.append(new_rgb) - book.colour_map[8+i] = new_rgb - if blah: - if new_rgb != old_rgb: - print("%2d: %r -> %r" % (i, old_rgb, new_rgb), file=book.logfile) - -def palette_epilogue(book): - # Check colour indexes in fonts etc. - # This must be done here as FONT records - # come *before* the PALETTE record :-( - for font in book.font_list: - if font.font_index == 4: # the missing font record - continue - cx = font.colour_index - if cx == 0x7fff: # system window text colour - continue - if cx in book.colour_map: - book.colour_indexes_used[cx] = 1 - elif book.verbosity: - print("Size of colour table:", len(book.colour_map), file=book.logfile) - fprintf(book.logfile, "*** Font #%d (%r): colour index 0x%04x is unknown\n", - font.font_index, font.name, cx) - if book.verbosity >= 1: - used = sorted(book.colour_indexes_used.keys()) - print("\nColour indexes used:\n%r\n" % used, file=book.logfile) - -def handle_style(book, data): - if not book.formatting_info: - return - blah = DEBUG or book.verbosity >= 2 - bv = book.biff_version - flag_and_xfx, built_in_id, level = unpack('= 80: - try: - name = unpack_unicode(data, 2, lenlen=2) - except UnicodeDecodeError: - print("STYLE: built_in=%d xf_index=%d built_in_id=%d level=%d" \ - % (built_in, xf_index, built_in_id, level), file=book.logfile) - print("raw bytes:", repr(data[2:]), file=book.logfile) - raise - else: - name = unpack_string(data, 2, book.encoding, lenlen=1) - if blah and not name: - print("WARNING *** A user-defined style has a zero-length name", file=book.logfile) - book.style_name_map[name] = (built_in, xf_index) - if blah: - fprintf(book.logfile, "STYLE: built_in=%d xf_index=%d built_in_id=%d level=%d name=%r\n", - built_in, xf_index, built_in_id, level, name) - -def check_colour_indexes_in_obj(book, obj, orig_index): - alist = sorted(obj.__dict__.items()) - for attr, nobj in alist: - if hasattr(nobj, 'dump'): - check_colour_indexes_in_obj(book, nobj, orig_index) - elif attr.find('colour_index') >= 0: - if nobj in book.colour_map: - book.colour_indexes_used[nobj] = 1 - continue - oname = obj.__class__.__name__ - print("*** xf #%d : %s.%s = 0x%04x (unknown)" \ - % (orig_index, oname, attr, nobj), file=book.logfile) - -def fill_in_standard_formats(book): - for x in std_format_code_types.keys(): - if x not in book.format_map: - ty = std_format_code_types[x] - # Note: many standard format codes (mostly CJK date formats) have - # format strings that vary by locale; xlrd does not (yet) - # handle those; the type (date or numeric) is recorded but the fmt_str will be None. - fmt_str = std_format_strings.get(x) - fmtobj = Format(x, ty, fmt_str) - book.format_map[x] = fmtobj - -def handle_xf(self, data): - ### self is a Book instance - # DEBUG = 0 - blah = DEBUG or self.verbosity >= 3 - bv = self.biff_version - xf = XF() - xf.alignment = XFAlignment() - xf.alignment.indent_level = 0 - xf.alignment.shrink_to_fit = 0 - xf.alignment.text_direction = 0 - xf.border = XFBorder() - xf.border.diag_up = 0 - xf.border.diag_down = 0 - xf.border.diag_colour_index = 0 - xf.border.diag_line_style = 0 # no line - xf.background = XFBackground() - xf.protection = XFProtection() - # fill in the known standard formats - if bv >= 50 and not self.xfcount: - # i.e. do this once before we process the first XF record - fill_in_standard_formats(self) - if bv >= 80: - unpack_fmt = '> 2 - for attr_stem in \ - "format font alignment border background protection".split(): - attr = "_" + attr_stem + "_flag" - setattr(xf, attr, reg & 1) - reg >>= 1 - upkbitsL(xf.border, pkd_brdbkg1, ( - (0, 0x0000000f, 'left_line_style'), - (4, 0x000000f0, 'right_line_style'), - (8, 0x00000f00, 'top_line_style'), - (12, 0x0000f000, 'bottom_line_style'), - (16, 0x007f0000, 'left_colour_index'), - (23, 0x3f800000, 'right_colour_index'), - (30, 0x40000000, 'diag_down'), - (31, 0x80000000, 'diag_up'), - )) - upkbits(xf.border, pkd_brdbkg2, ( - (0, 0x0000007F, 'top_colour_index'), - (7, 0x00003F80, 'bottom_colour_index'), - (14, 0x001FC000, 'diag_colour_index'), - (21, 0x01E00000, 'diag_line_style'), - )) - upkbitsL(xf.background, pkd_brdbkg2, ( - (26, 0xFC000000, 'fill_pattern'), - )) - upkbits(xf.background, pkd_brdbkg3, ( - (0, 0x007F, 'pattern_colour_index'), - (7, 0x3F80, 'background_colour_index'), - )) - elif bv >= 50: - unpack_fmt = '> 2 - for attr_stem in \ - "format font alignment border background protection".split(): - attr = "_" + attr_stem + "_flag" - setattr(xf, attr, reg & 1) - reg >>= 1 - upkbitsL(xf.background, pkd_brdbkg1, ( - ( 0, 0x0000007F, 'pattern_colour_index'), - ( 7, 0x00003F80, 'background_colour_index'), - (16, 0x003F0000, 'fill_pattern'), - )) - upkbitsL(xf.border, pkd_brdbkg1, ( - (22, 0x01C00000, 'bottom_line_style'), - (25, 0xFE000000, 'bottom_colour_index'), - )) - upkbits(xf.border, pkd_brdbkg2, ( - ( 0, 0x00000007, 'top_line_style'), - ( 3, 0x00000038, 'left_line_style'), - ( 6, 0x000001C0, 'right_line_style'), - ( 9, 0x0000FE00, 'top_colour_index'), - (16, 0x007F0000, 'left_colour_index'), - (23, 0x3F800000, 'right_colour_index'), - )) - elif bv >= 40: - unpack_fmt = '> 6 - xf.alignment.rotation = [0, 255, 90, 180][orientation] - reg = pkd_used >> 2 - for attr_stem in \ - "format font alignment border background protection".split(): - attr = "_" + attr_stem + "_flag" - setattr(xf, attr, reg & 1) - reg >>= 1 - upkbits(xf.background, pkd_bkg_34, ( - ( 0, 0x003F, 'fill_pattern'), - ( 6, 0x07C0, 'pattern_colour_index'), - (11, 0xF800, 'background_colour_index'), - )) - upkbitsL(xf.border, pkd_brd_34, ( - ( 0, 0x00000007, 'top_line_style'), - ( 3, 0x000000F8, 'top_colour_index'), - ( 8, 0x00000700, 'left_line_style'), - (11, 0x0000F800, 'left_colour_index'), - (16, 0x00070000, 'bottom_line_style'), - (19, 0x00F80000, 'bottom_colour_index'), - (24, 0x07000000, 'right_line_style'), - (27, 0xF8000000, 'right_colour_index'), - )) - elif bv == 30: - unpack_fmt = '> 2 - for attr_stem in \ - "format font alignment border background protection".split(): - attr = "_" + attr_stem + "_flag" - setattr(xf, attr, reg & 1) - reg >>= 1 - upkbits(xf.background, pkd_bkg_34, ( - ( 0, 0x003F, 'fill_pattern'), - ( 6, 0x07C0, 'pattern_colour_index'), - (11, 0xF800, 'background_colour_index'), - )) - upkbitsL(xf.border, pkd_brd_34, ( - ( 0, 0x00000007, 'top_line_style'), - ( 3, 0x000000F8, 'top_colour_index'), - ( 8, 0x00000700, 'left_line_style'), - (11, 0x0000F800, 'left_colour_index'), - (16, 0x00070000, 'bottom_line_style'), - (19, 0x00F80000, 'bottom_colour_index'), - (24, 0x07000000, 'right_line_style'), - (27, 0xF8000000, 'right_colour_index'), - )) - xf.alignment.vert_align = 2 # bottom - xf.alignment.rotation = 0 - elif bv == 21: - #### Warning: incomplete treatment; formatting_info not fully supported. - #### Probably need to offset incoming BIFF2 XF[n] to BIFF8-like XF[n+16], - #### and create XF[0:16] like the standard ones in BIFF8 - #### *AND* add 16 to all XF references in cell records :-( - (xf.font_index, format_etc, halign_etc) = unpack('= 3 - blah1 = DEBUG or self.verbosity >= 1 - if blah: - fprintf(self.logfile, "xf_epilogue called ...\n") - - def check_same(book_arg, xf_arg, parent_arg, attr): - # the _arg caper is to avoid a Warning msg from Python 2.1 :-( - if getattr(xf_arg, attr) != getattr(parent_arg, attr): - fprintf(book_arg.logfile, - "NOTE !!! XF[%d] parent[%d] %s different\n", - xf_arg.xf_index, parent_arg.xf_index, attr) - - for xfx in xrange(num_xfs): - xf = self.xf_list[xfx] - if xf.format_key not in self.format_map: - msg = "ERROR *** XF[%d] unknown format key (%d, 0x%04x)\n" - fprintf(self.logfile, msg, - xf.xf_index, xf.format_key, xf.format_key) - xf.format_key = 0 - - fmt = self.format_map[xf.format_key] - cellty = _cellty_from_fmtty[fmt.type] - self._xf_index_to_xl_type_map[xf.xf_index] = cellty - # Now for some assertions etc - if not self.formatting_info: - continue - if xf.is_style: - continue - if not(0 <= xf.parent_style_index < num_xfs): - if blah1: - fprintf(self.logfile, - "WARNING *** XF[%d]: is_style=%d but parent_style_index=%d\n", - xf.xf_index, xf.is_style, xf.parent_style_index) - # make it conform - xf.parent_style_index = 0 - if self.biff_version >= 30: - if blah1: - if xf.parent_style_index == xf.xf_index: - fprintf(self.logfile, - "NOTE !!! XF[%d]: parent_style_index is also %d\n", - xf.xf_index, xf.parent_style_index) - elif not self.xf_list[xf.parent_style_index].is_style: - fprintf(self.logfile, - "NOTE !!! XF[%d]: parent_style_index is %d; style flag not set\n", - xf.xf_index, xf.parent_style_index) - if blah1 and xf.parent_style_index > xf.xf_index: - fprintf(self.logfile, - "NOTE !!! XF[%d]: parent_style_index is %d; out of order?\n", - xf.xf_index, xf.parent_style_index) - parent = self.xf_list[xf.parent_style_index] - if not xf._alignment_flag and not parent._alignment_flag: - if blah1: check_same(self, xf, parent, 'alignment') - if not xf._background_flag and not parent._background_flag: - if blah1: check_same(self, xf, parent, 'background') - if not xf._border_flag and not parent._border_flag: - if blah1: check_same(self, xf, parent, 'border') - if not xf._protection_flag and not parent._protection_flag: - if blah1: check_same(self, xf, parent, 'protection') - if not xf._format_flag and not parent._format_flag: - if blah1 and xf.format_key != parent.format_key: - fprintf(self.logfile, - "NOTE !!! XF[%d] fmtk=%d, parent[%d] fmtk=%r\n%r / %r\n", - xf.xf_index, xf.format_key, parent.xf_index, parent.format_key, - self.format_map[xf.format_key].format_str, - self.format_map[parent.format_key].format_str) - if not xf._font_flag and not parent._font_flag: - if blah1 and xf.font_index != parent.font_index: - fprintf(self.logfile, - "NOTE !!! XF[%d] fontx=%d, parent[%d] fontx=%r\n", - xf.xf_index, xf.font_index, parent.xf_index, parent.font_index) - -def initialise_book(book): - initialise_colour_map(book) - book._xf_epilogue_done = 0 - methods = ( - handle_font, - handle_efont, - handle_format, - is_date_format_string, - handle_palette, - palette_epilogue, - handle_style, - handle_xf, - xf_epilogue, - ) - for method in methods: - setattr(book.__class__, method.__name__, method) - -## -#

    A collection of the border-related attributes of an XF record. -# Items correspond to those in the Excel UI's Format/Cells/Border tab.

    -#

    An explanations of "colour index" is given in the Formatting -# section at the start of this document. -# There are five line style attributes; possible values and the -# associated meanings are: -# 0 = No line, -# 1 = Thin, -# 2 = Medium, -# 3 = Dashed, -# 4 = Dotted, -# 5 = Thick, -# 6 = Double, -# 7 = Hair, -# 8 = Medium dashed, -# 9 = Thin dash-dotted, -# 10 = Medium dash-dotted, -# 11 = Thin dash-dot-dotted, -# 12 = Medium dash-dot-dotted, -# 13 = Slanted medium dash-dotted. -# The line styles 8 to 13 appear in BIFF8 files (Excel 97 and later) only. -# For pictures of the line styles, refer to OOo docs s3.10 (p22) -# "Line Styles for Cell Borders (BIFF3-BIFF8)".

    -#
    -- New in version 0.6.1 -class XFBorder(BaseObject, EqNeAttrs): - - ## - # The colour index for the cell's top line - top_colour_index = 0 - ## - # The colour index for the cell's bottom line - bottom_colour_index = 0 - ## - # The colour index for the cell's left line - left_colour_index = 0 - ## - # The colour index for the cell's right line - right_colour_index = 0 - ## - # The colour index for the cell's diagonal lines, if any - diag_colour_index = 0 - ## - # The line style for the cell's top line - top_line_style = 0 - ## - # The line style for the cell's bottom line - bottom_line_style = 0 - ## - # The line style for the cell's left line - left_line_style = 0 - ## - # The line style for the cell's right line - right_line_style = 0 - ## - # The line style for the cell's diagonal lines, if any - diag_line_style = 0 - ## - # 1 = draw a diagonal from top left to bottom right - diag_down = 0 - ## - # 1 = draw a diagonal from bottom left to top right - diag_up = 0 - -## -# A collection of the background-related attributes of an XF record. -# Items correspond to those in the Excel UI's Format/Cells/Patterns tab. -# An explanation of "colour index" is given in the Formatting -# section at the start of this document. -#
    -- New in version 0.6.1 -class XFBackground(BaseObject, EqNeAttrs): - - ## - # See section 3.11 of the OOo docs. - fill_pattern = 0 - ## - # See section 3.11 of the OOo docs. - background_colour_index = 0 - ## - # See section 3.11 of the OOo docs. - pattern_colour_index = 0 - -## -# A collection of the alignment and similar attributes of an XF record. -# Items correspond to those in the Excel UI's Format/Cells/Alignment tab. -#
    -- New in version 0.6.1 - -class XFAlignment(BaseObject, EqNeAttrs): - - ## - # Values: section 6.115 (p 214) of OOo docs - hor_align = 0 - ## - # Values: section 6.115 (p 215) of OOo docs - vert_align = 0 - ## - # Values: section 6.115 (p 215) of OOo docs.
    - # Note: file versions BIFF7 and earlier use the documented - # "orientation" attribute; this will be mapped (without loss) - # into "rotation". - rotation = 0 - ## - # 1 = text is wrapped at right margin - text_wrapped = 0 - ## - # A number in range(15). - indent_level = 0 - ## - # 1 = shrink font size to fit text into cell. - shrink_to_fit = 0 - ## - # 0 = according to context; 1 = left-to-right; 2 = right-to-left - text_direction = 0 - -## -# A collection of the protection-related attributes of an XF record. -# Items correspond to those in the Excel UI's Format/Cells/Protection tab. -# Note the OOo docs include the "cell or style" bit -# in this bundle of attributes. -# This is incorrect; the bit is used in determining which bundles to use. -#
    -- New in version 0.6.1 - -class XFProtection(BaseObject, EqNeAttrs): - - ## - # 1 = Cell is prevented from being changed, moved, resized, or deleted - # (only if the sheet is protected). - cell_locked = 0 - ## - # 1 = Hide formula so that it doesn't appear in the formula bar when - # the cell is selected (only if the sheet is protected). - formula_hidden = 0 - -## -# eXtended Formatting information for cells, rows, columns and styles. -#
    -- New in version 0.6.1 -# -#

    Each of the 6 flags below describes the validity of -# a specific group of attributes. -#
    -# In cell XFs, flag==0 means the attributes of the parent style XF are used, -# (but only if the attributes are valid there); flag==1 means the attributes -# of this XF are used.
    -# In style XFs, flag==0 means the attribute setting is valid; flag==1 means -# the attribute should be ignored.
    -# Note that the API -# provides both "raw" XFs and "computed" XFs -- in the latter case, cell XFs -# have had the above inheritance mechanism applied. -#

    - -class XF(BaseObject): - - ## - # 0 = cell XF, 1 = style XF - is_style = 0 - ## - # cell XF: Index into Book.xf_list - # of this XF's style XF
    - # style XF: 0xFFF - parent_style_index = 0 - ## - # - _format_flag = 0 - ## - # - _font_flag = 0 - ## - # - _alignment_flag = 0 - ## - # - _border_flag = 0 - ## - # - _background_flag = 0 - ## - #   - _protection_flag = 0 - ## - # Index into Book.xf_list - xf_index = 0 - ## - # Index into Book.font_list - font_index = 0 - ## - # Key into Book.format_map - #

    - # Warning: OOo docs on the XF record call this "Index to FORMAT record". - # It is not an index in the Python sense. It is a key to a map. - # It is true only for Excel 4.0 and earlier files - # that the key into format_map from an XF instance - # is the same as the index into format_list, and only - # if the index is less than 164. - #

    - format_key = 0 - ## - # An instance of an XFProtection object. - protection = None - ## - # An instance of an XFBackground object. - background = None - ## - # An instance of an XFAlignment object. - alignment = None - ## - # An instance of an XFBorder object. - border = None diff --git a/webhub/xlrd/formatting.pyc b/webhub/xlrd/formatting.pyc deleted file mode 100644 index 4e2040bf..00000000 Binary files a/webhub/xlrd/formatting.pyc and /dev/null differ diff --git a/webhub/xlrd/formula.py b/webhub/xlrd/formula.py deleted file mode 100644 index 7c56aa4f..00000000 --- a/webhub/xlrd/formula.py +++ /dev/null @@ -1,2179 +0,0 @@ -# -*- coding: cp1252 -*- - -## -# Module for parsing/evaluating Microsoft Excel formulas. -# -#

    Copyright 2005-2012 Stephen John Machin, Lingfo Pty Ltd

    -#

    This module is part of the xlrd package, which is released under -# a BSD-style licence.

    -## - -# No part of the content of this file was derived from the works of David Giffin. - -from __future__ import print_function -import copy -from struct import unpack -from .timemachine import * -from .biffh import unpack_unicode_update_pos, unpack_string_update_pos, \ - XLRDError, hex_char_dump, error_text_from_code, BaseObject - -__all__ = [ - 'oBOOL', 'oERR', 'oNUM', 'oREF', 'oREL', 'oSTRG', 'oUNK', - 'decompile_formula', - 'dump_formula', - 'evaluate_name_formula', - 'okind_dict', - 'rangename3d', 'rangename3drel', 'cellname', 'cellnameabs', 'colname', - 'FMLA_TYPE_CELL', - 'FMLA_TYPE_SHARED', - 'FMLA_TYPE_ARRAY', - 'FMLA_TYPE_COND_FMT', - 'FMLA_TYPE_DATA_VAL', - 'FMLA_TYPE_NAME', - ] - -FMLA_TYPE_CELL = 1 -FMLA_TYPE_SHARED = 2 -FMLA_TYPE_ARRAY = 4 -FMLA_TYPE_COND_FMT = 8 -FMLA_TYPE_DATA_VAL = 16 -FMLA_TYPE_NAME = 32 -ALL_FMLA_TYPES = 63 - - -FMLA_TYPEDESCR_MAP = { - 1 : 'CELL', - 2 : 'SHARED', - 4 : 'ARRAY', - 8 : 'COND-FMT', - 16: 'DATA-VAL', - 32: 'NAME', - } - -_TOKEN_NOT_ALLOWED = { - 0x01: ALL_FMLA_TYPES - FMLA_TYPE_CELL, # tExp - 0x02: ALL_FMLA_TYPES - FMLA_TYPE_CELL, # tTbl - 0x0F: FMLA_TYPE_SHARED + FMLA_TYPE_COND_FMT + FMLA_TYPE_DATA_VAL, # tIsect - 0x10: FMLA_TYPE_SHARED + FMLA_TYPE_COND_FMT + FMLA_TYPE_DATA_VAL, # tUnion/List - 0x11: FMLA_TYPE_SHARED + FMLA_TYPE_COND_FMT + FMLA_TYPE_DATA_VAL, # tRange - 0x20: FMLA_TYPE_SHARED + FMLA_TYPE_COND_FMT + FMLA_TYPE_DATA_VAL, # tArray - 0x23: FMLA_TYPE_SHARED, # tName - 0x39: FMLA_TYPE_SHARED + FMLA_TYPE_COND_FMT + FMLA_TYPE_DATA_VAL, # tNameX - 0x3A: FMLA_TYPE_SHARED + FMLA_TYPE_COND_FMT + FMLA_TYPE_DATA_VAL, # tRef3d - 0x3B: FMLA_TYPE_SHARED + FMLA_TYPE_COND_FMT + FMLA_TYPE_DATA_VAL, # tArea3d - 0x2C: FMLA_TYPE_CELL + FMLA_TYPE_ARRAY, # tRefN - 0x2D: FMLA_TYPE_CELL + FMLA_TYPE_ARRAY, # tAreaN - # plus weird stuff like tMem* - }.get - -oBOOL = 3 -oERR = 4 -oMSNG = 5 # tMissArg -oNUM = 2 -oREF = -1 -oREL = -2 -oSTRG = 1 -oUNK = 0 - -okind_dict = { - -2: "oREL", - -1: "oREF", - 0 : "oUNK", - 1 : "oSTRG", - 2 : "oNUM", - 3 : "oBOOL", - 4 : "oERR", - 5 : "oMSNG", - } - -listsep = ',' #### probably should depend on locale - - -# sztabN[opcode] -> the number of bytes to consume. -# -1 means variable -# -2 means this opcode not implemented in this version. -# Which N to use? Depends on biff_version; see szdict. -sztab0 = [-2, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -2, -1, 8, 4, 2, 2, 3, 9, 8, 2, 3, 8, 4, 7, 5, 5, 5, 2, 4, 7, 4, 7, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2, 3, -2, -2, -2, -2, -2, -2, -2] -sztab1 = [-2, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -2, -1, 11, 5, 2, 2, 3, 9, 9, 2, 3, 11, 4, 7, 7, 7, 7, 3, 4, 7, 4, 7, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2, 3, -2, -2, -2, -2, -2, -2, -2] -sztab2 = [-2, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -2, -1, 11, 5, 2, 2, 3, 9, 9, 3, 4, 11, 4, 7, 7, 7, 7, 3, 4, 7, 4, 7, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2] -sztab3 = [-2, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -2, -1, -2, -2, 2, 2, 3, 9, 9, 3, 4, 15, 4, 7, 7, 7, 7, 3, 4, 7, 4, 7, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2, -2, 25, 18, 21, 18, 21, -2, -2] -sztab4 = [-2, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -2, -2, 2, 2, 3, 9, 9, 3, 4, 5, 5, 9, 7, 7, 7, 3, 5, 9, 5, 9, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2, -2, 7, 7, 11, 7, 11, -2, -2] - -szdict = { - 20 : sztab0, - 21 : sztab0, - 30 : sztab1, - 40 : sztab2, - 45 : sztab2, - 50 : sztab3, - 70 : sztab3, - 80 : sztab4, - } - -# For debugging purposes ... the name for each opcode -# (without the prefix "t" used on OOo docs) -onames = ['Unk00', 'Exp', 'Tbl', 'Add', 'Sub', 'Mul', 'Div', 'Power', 'Concat', 'LT', 'LE', 'EQ', 'GE', 'GT', 'NE', 'Isect', 'List', 'Range', 'Uplus', 'Uminus', 'Percent', 'Paren', 'MissArg', 'Str', 'Extended', 'Attr', 'Sheet', 'EndSheet', 'Err', 'Bool', 'Int', 'Num', 'Array', 'Func', 'FuncVar', 'Name', 'Ref', 'Area', 'MemArea', 'MemErr', 'MemNoMem', 'MemFunc', 'RefErr', 'AreaErr', 'RefN', 'AreaN', 'MemAreaN', 'MemNoMemN', '', '', '', '', '', '', '', '', 'FuncCE', 'NameX', 'Ref3d', 'Area3d', 'RefErr3d', 'AreaErr3d', '', ''] - -func_defs = { - # index: (name, min#args, max#args, flags, #known_args, return_type, kargs) - 0 : ('COUNT', 0, 30, 0x04, 1, 'V', 'R'), - 1 : ('IF', 2, 3, 0x04, 3, 'V', 'VRR'), - 2 : ('ISNA', 1, 1, 0x02, 1, 'V', 'V'), - 3 : ('ISERROR', 1, 1, 0x02, 1, 'V', 'V'), - 4 : ('SUM', 0, 30, 0x04, 1, 'V', 'R'), - 5 : ('AVERAGE', 1, 30, 0x04, 1, 'V', 'R'), - 6 : ('MIN', 1, 30, 0x04, 1, 'V', 'R'), - 7 : ('MAX', 1, 30, 0x04, 1, 'V', 'R'), - 8 : ('ROW', 0, 1, 0x04, 1, 'V', 'R'), - 9 : ('COLUMN', 0, 1, 0x04, 1, 'V', 'R'), - 10 : ('NA', 0, 0, 0x02, 0, 'V', ''), - 11 : ('NPV', 2, 30, 0x04, 2, 'V', 'VR'), - 12 : ('STDEV', 1, 30, 0x04, 1, 'V', 'R'), - 13 : ('DOLLAR', 1, 2, 0x04, 1, 'V', 'V'), - 14 : ('FIXED', 2, 3, 0x04, 3, 'V', 'VVV'), - 15 : ('SIN', 1, 1, 0x02, 1, 'V', 'V'), - 16 : ('COS', 1, 1, 0x02, 1, 'V', 'V'), - 17 : ('TAN', 1, 1, 0x02, 1, 'V', 'V'), - 18 : ('ATAN', 1, 1, 0x02, 1, 'V', 'V'), - 19 : ('PI', 0, 0, 0x02, 0, 'V', ''), - 20 : ('SQRT', 1, 1, 0x02, 1, 'V', 'V'), - 21 : ('EXP', 1, 1, 0x02, 1, 'V', 'V'), - 22 : ('LN', 1, 1, 0x02, 1, 'V', 'V'), - 23 : ('LOG10', 1, 1, 0x02, 1, 'V', 'V'), - 24 : ('ABS', 1, 1, 0x02, 1, 'V', 'V'), - 25 : ('INT', 1, 1, 0x02, 1, 'V', 'V'), - 26 : ('SIGN', 1, 1, 0x02, 1, 'V', 'V'), - 27 : ('ROUND', 2, 2, 0x02, 2, 'V', 'VV'), - 28 : ('LOOKUP', 2, 3, 0x04, 2, 'V', 'VR'), - 29 : ('INDEX', 2, 4, 0x0c, 4, 'R', 'RVVV'), - 30 : ('REPT', 2, 2, 0x02, 2, 'V', 'VV'), - 31 : ('MID', 3, 3, 0x02, 3, 'V', 'VVV'), - 32 : ('LEN', 1, 1, 0x02, 1, 'V', 'V'), - 33 : ('VALUE', 1, 1, 0x02, 1, 'V', 'V'), - 34 : ('TRUE', 0, 0, 0x02, 0, 'V', ''), - 35 : ('FALSE', 0, 0, 0x02, 0, 'V', ''), - 36 : ('AND', 1, 30, 0x04, 1, 'V', 'R'), - 37 : ('OR', 1, 30, 0x04, 1, 'V', 'R'), - 38 : ('NOT', 1, 1, 0x02, 1, 'V', 'V'), - 39 : ('MOD', 2, 2, 0x02, 2, 'V', 'VV'), - 40 : ('DCOUNT', 3, 3, 0x02, 3, 'V', 'RRR'), - 41 : ('DSUM', 3, 3, 0x02, 3, 'V', 'RRR'), - 42 : ('DAVERAGE', 3, 3, 0x02, 3, 'V', 'RRR'), - 43 : ('DMIN', 3, 3, 0x02, 3, 'V', 'RRR'), - 44 : ('DMAX', 3, 3, 0x02, 3, 'V', 'RRR'), - 45 : ('DSTDEV', 3, 3, 0x02, 3, 'V', 'RRR'), - 46 : ('VAR', 1, 30, 0x04, 1, 'V', 'R'), - 47 : ('DVAR', 3, 3, 0x02, 3, 'V', 'RRR'), - 48 : ('TEXT', 2, 2, 0x02, 2, 'V', 'VV'), - 49 : ('LINEST', 1, 4, 0x04, 4, 'A', 'RRVV'), - 50 : ('TREND', 1, 4, 0x04, 4, 'A', 'RRRV'), - 51 : ('LOGEST', 1, 4, 0x04, 4, 'A', 'RRVV'), - 52 : ('GROWTH', 1, 4, 0x04, 4, 'A', 'RRRV'), - 56 : ('PV', 3, 5, 0x04, 5, 'V', 'VVVVV'), - 57 : ('FV', 3, 5, 0x04, 5, 'V', 'VVVVV'), - 58 : ('NPER', 3, 5, 0x04, 5, 'V', 'VVVVV'), - 59 : ('PMT', 3, 5, 0x04, 5, 'V', 'VVVVV'), - 60 : ('RATE', 3, 6, 0x04, 6, 'V', 'VVVVVV'), - 61 : ('MIRR', 3, 3, 0x02, 3, 'V', 'RVV'), - 62 : ('IRR', 1, 2, 0x04, 2, 'V', 'RV'), - 63 : ('RAND', 0, 0, 0x0a, 0, 'V', ''), - 64 : ('MATCH', 2, 3, 0x04, 3, 'V', 'VRR'), - 65 : ('DATE', 3, 3, 0x02, 3, 'V', 'VVV'), - 66 : ('TIME', 3, 3, 0x02, 3, 'V', 'VVV'), - 67 : ('DAY', 1, 1, 0x02, 1, 'V', 'V'), - 68 : ('MONTH', 1, 1, 0x02, 1, 'V', 'V'), - 69 : ('YEAR', 1, 1, 0x02, 1, 'V', 'V'), - 70 : ('WEEKDAY', 1, 2, 0x04, 2, 'V', 'VV'), - 71 : ('HOUR', 1, 1, 0x02, 1, 'V', 'V'), - 72 : ('MINUTE', 1, 1, 0x02, 1, 'V', 'V'), - 73 : ('SECOND', 1, 1, 0x02, 1, 'V', 'V'), - 74 : ('NOW', 0, 0, 0x0a, 0, 'V', ''), - 75 : ('AREAS', 1, 1, 0x02, 1, 'V', 'R'), - 76 : ('ROWS', 1, 1, 0x02, 1, 'V', 'R'), - 77 : ('COLUMNS', 1, 1, 0x02, 1, 'V', 'R'), - 78 : ('OFFSET', 3, 5, 0x04, 5, 'R', 'RVVVV'), - 82 : ('SEARCH', 2, 3, 0x04, 3, 'V', 'VVV'), - 83 : ('TRANSPOSE', 1, 1, 0x02, 1, 'A', 'A'), - 86 : ('TYPE', 1, 1, 0x02, 1, 'V', 'V'), - 92 : ('SERIESSUM', 4, 4, 0x02, 4, 'V', 'VVVA'), - 97 : ('ATAN2', 2, 2, 0x02, 2, 'V', 'VV'), - 98 : ('ASIN', 1, 1, 0x02, 1, 'V', 'V'), - 99 : ('ACOS', 1, 1, 0x02, 1, 'V', 'V'), - 100: ('CHOOSE', 2, 30, 0x04, 2, 'V', 'VR'), - 101: ('HLOOKUP', 3, 4, 0x04, 4, 'V', 'VRRV'), - 102: ('VLOOKUP', 3, 4, 0x04, 4, 'V', 'VRRV'), - 105: ('ISREF', 1, 1, 0x02, 1, 'V', 'R'), - 109: ('LOG', 1, 2, 0x04, 2, 'V', 'VV'), - 111: ('CHAR', 1, 1, 0x02, 1, 'V', 'V'), - 112: ('LOWER', 1, 1, 0x02, 1, 'V', 'V'), - 113: ('UPPER', 1, 1, 0x02, 1, 'V', 'V'), - 114: ('PROPER', 1, 1, 0x02, 1, 'V', 'V'), - 115: ('LEFT', 1, 2, 0x04, 2, 'V', 'VV'), - 116: ('RIGHT', 1, 2, 0x04, 2, 'V', 'VV'), - 117: ('EXACT', 2, 2, 0x02, 2, 'V', 'VV'), - 118: ('TRIM', 1, 1, 0x02, 1, 'V', 'V'), - 119: ('REPLACE', 4, 4, 0x02, 4, 'V', 'VVVV'), - 120: ('SUBSTITUTE', 3, 4, 0x04, 4, 'V', 'VVVV'), - 121: ('CODE', 1, 1, 0x02, 1, 'V', 'V'), - 124: ('FIND', 2, 3, 0x04, 3, 'V', 'VVV'), - 125: ('CELL', 1, 2, 0x0c, 2, 'V', 'VR'), - 126: ('ISERR', 1, 1, 0x02, 1, 'V', 'V'), - 127: ('ISTEXT', 1, 1, 0x02, 1, 'V', 'V'), - 128: ('ISNUMBER', 1, 1, 0x02, 1, 'V', 'V'), - 129: ('ISBLANK', 1, 1, 0x02, 1, 'V', 'V'), - 130: ('T', 1, 1, 0x02, 1, 'V', 'R'), - 131: ('N', 1, 1, 0x02, 1, 'V', 'R'), - 140: ('DATEVALUE', 1, 1, 0x02, 1, 'V', 'V'), - 141: ('TIMEVALUE', 1, 1, 0x02, 1, 'V', 'V'), - 142: ('SLN', 3, 3, 0x02, 3, 'V', 'VVV'), - 143: ('SYD', 4, 4, 0x02, 4, 'V', 'VVVV'), - 144: ('DDB', 4, 5, 0x04, 5, 'V', 'VVVVV'), - 148: ('INDIRECT', 1, 2, 0x0c, 2, 'R', 'VV'), - 162: ('CLEAN', 1, 1, 0x02, 1, 'V', 'V'), - 163: ('MDETERM', 1, 1, 0x02, 1, 'V', 'A'), - 164: ('MINVERSE', 1, 1, 0x02, 1, 'A', 'A'), - 165: ('MMULT', 2, 2, 0x02, 2, 'A', 'AA'), - 167: ('IPMT', 4, 6, 0x04, 6, 'V', 'VVVVVV'), - 168: ('PPMT', 4, 6, 0x04, 6, 'V', 'VVVVVV'), - 169: ('COUNTA', 0, 30, 0x04, 1, 'V', 'R'), - 183: ('PRODUCT', 0, 30, 0x04, 1, 'V', 'R'), - 184: ('FACT', 1, 1, 0x02, 1, 'V', 'V'), - 189: ('DPRODUCT', 3, 3, 0x02, 3, 'V', 'RRR'), - 190: ('ISNONTEXT', 1, 1, 0x02, 1, 'V', 'V'), - 193: ('STDEVP', 1, 30, 0x04, 1, 'V', 'R'), - 194: ('VARP', 1, 30, 0x04, 1, 'V', 'R'), - 195: ('DSTDEVP', 3, 3, 0x02, 3, 'V', 'RRR'), - 196: ('DVARP', 3, 3, 0x02, 3, 'V', 'RRR'), - 197: ('TRUNC', 1, 2, 0x04, 2, 'V', 'VV'), - 198: ('ISLOGICAL', 1, 1, 0x02, 1, 'V', 'V'), - 199: ('DCOUNTA', 3, 3, 0x02, 3, 'V', 'RRR'), - 204: ('USDOLLAR', 1, 2, 0x04, 2, 'V', 'VV'), - 205: ('FINDB', 2, 3, 0x04, 3, 'V', 'VVV'), - 206: ('SEARCHB', 2, 3, 0x04, 3, 'V', 'VVV'), - 207: ('REPLACEB', 4, 4, 0x02, 4, 'V', 'VVVV'), - 208: ('LEFTB', 1, 2, 0x04, 2, 'V', 'VV'), - 209: ('RIGHTB', 1, 2, 0x04, 2, 'V', 'VV'), - 210: ('MIDB', 3, 3, 0x02, 3, 'V', 'VVV'), - 211: ('LENB', 1, 1, 0x02, 1, 'V', 'V'), - 212: ('ROUNDUP', 2, 2, 0x02, 2, 'V', 'VV'), - 213: ('ROUNDDOWN', 2, 2, 0x02, 2, 'V', 'VV'), - 214: ('ASC', 1, 1, 0x02, 1, 'V', 'V'), - 215: ('DBCS', 1, 1, 0x02, 1, 'V', 'V'), - 216: ('RANK', 2, 3, 0x04, 3, 'V', 'VRV'), - 219: ('ADDRESS', 2, 5, 0x04, 5, 'V', 'VVVVV'), - 220: ('DAYS360', 2, 3, 0x04, 3, 'V', 'VVV'), - 221: ('TODAY', 0, 0, 0x0a, 0, 'V', ''), - 222: ('VDB', 5, 7, 0x04, 7, 'V', 'VVVVVVV'), - 227: ('MEDIAN', 1, 30, 0x04, 1, 'V', 'R'), - 228: ('SUMPRODUCT', 1, 30, 0x04, 1, 'V', 'A'), - 229: ('SINH', 1, 1, 0x02, 1, 'V', 'V'), - 230: ('COSH', 1, 1, 0x02, 1, 'V', 'V'), - 231: ('TANH', 1, 1, 0x02, 1, 'V', 'V'), - 232: ('ASINH', 1, 1, 0x02, 1, 'V', 'V'), - 233: ('ACOSH', 1, 1, 0x02, 1, 'V', 'V'), - 234: ('ATANH', 1, 1, 0x02, 1, 'V', 'V'), - 235: ('DGET', 3, 3, 0x02, 3, 'V', 'RRR'), - 244: ('INFO', 1, 1, 0x02, 1, 'V', 'V'), - 247: ('DB', 4, 5, 0x04, 5, 'V', 'VVVVV'), - 252: ('FREQUENCY', 2, 2, 0x02, 2, 'A', 'RR'), - 261: ('ERROR.TYPE', 1, 1, 0x02, 1, 'V', 'V'), - 269: ('AVEDEV', 1, 30, 0x04, 1, 'V', 'R'), - 270: ('BETADIST', 3, 5, 0x04, 1, 'V', 'V'), - 271: ('GAMMALN', 1, 1, 0x02, 1, 'V', 'V'), - 272: ('BETAINV', 3, 5, 0x04, 1, 'V', 'V'), - 273: ('BINOMDIST', 4, 4, 0x02, 4, 'V', 'VVVV'), - 274: ('CHIDIST', 2, 2, 0x02, 2, 'V', 'VV'), - 275: ('CHIINV', 2, 2, 0x02, 2, 'V', 'VV'), - 276: ('COMBIN', 2, 2, 0x02, 2, 'V', 'VV'), - 277: ('CONFIDENCE', 3, 3, 0x02, 3, 'V', 'VVV'), - 278: ('CRITBINOM', 3, 3, 0x02, 3, 'V', 'VVV'), - 279: ('EVEN', 1, 1, 0x02, 1, 'V', 'V'), - 280: ('EXPONDIST', 3, 3, 0x02, 3, 'V', 'VVV'), - 281: ('FDIST', 3, 3, 0x02, 3, 'V', 'VVV'), - 282: ('FINV', 3, 3, 0x02, 3, 'V', 'VVV'), - 283: ('FISHER', 1, 1, 0x02, 1, 'V', 'V'), - 284: ('FISHERINV', 1, 1, 0x02, 1, 'V', 'V'), - 285: ('FLOOR', 2, 2, 0x02, 2, 'V', 'VV'), - 286: ('GAMMADIST', 4, 4, 0x02, 4, 'V', 'VVVV'), - 287: ('GAMMAINV', 3, 3, 0x02, 3, 'V', 'VVV'), - 288: ('CEILING', 2, 2, 0x02, 2, 'V', 'VV'), - 289: ('HYPGEOMDIST', 4, 4, 0x02, 4, 'V', 'VVVV'), - 290: ('LOGNORMDIST', 3, 3, 0x02, 3, 'V', 'VVV'), - 291: ('LOGINV', 3, 3, 0x02, 3, 'V', 'VVV'), - 292: ('NEGBINOMDIST', 3, 3, 0x02, 3, 'V', 'VVV'), - 293: ('NORMDIST', 4, 4, 0x02, 4, 'V', 'VVVV'), - 294: ('NORMSDIST', 1, 1, 0x02, 1, 'V', 'V'), - 295: ('NORMINV', 3, 3, 0x02, 3, 'V', 'VVV'), - 296: ('NORMSINV', 1, 1, 0x02, 1, 'V', 'V'), - 297: ('STANDARDIZE', 3, 3, 0x02, 3, 'V', 'VVV'), - 298: ('ODD', 1, 1, 0x02, 1, 'V', 'V'), - 299: ('PERMUT', 2, 2, 0x02, 2, 'V', 'VV'), - 300: ('POISSON', 3, 3, 0x02, 3, 'V', 'VVV'), - 301: ('TDIST', 3, 3, 0x02, 3, 'V', 'VVV'), - 302: ('WEIBULL', 4, 4, 0x02, 4, 'V', 'VVVV'), - 303: ('SUMXMY2', 2, 2, 0x02, 2, 'V', 'AA'), - 304: ('SUMX2MY2', 2, 2, 0x02, 2, 'V', 'AA'), - 305: ('SUMX2PY2', 2, 2, 0x02, 2, 'V', 'AA'), - 306: ('CHITEST', 2, 2, 0x02, 2, 'V', 'AA'), - 307: ('CORREL', 2, 2, 0x02, 2, 'V', 'AA'), - 308: ('COVAR', 2, 2, 0x02, 2, 'V', 'AA'), - 309: ('FORECAST', 3, 3, 0x02, 3, 'V', 'VAA'), - 310: ('FTEST', 2, 2, 0x02, 2, 'V', 'AA'), - 311: ('INTERCEPT', 2, 2, 0x02, 2, 'V', 'AA'), - 312: ('PEARSON', 2, 2, 0x02, 2, 'V', 'AA'), - 313: ('RSQ', 2, 2, 0x02, 2, 'V', 'AA'), - 314: ('STEYX', 2, 2, 0x02, 2, 'V', 'AA'), - 315: ('SLOPE', 2, 2, 0x02, 2, 'V', 'AA'), - 316: ('TTEST', 4, 4, 0x02, 4, 'V', 'AAVV'), - 317: ('PROB', 3, 4, 0x04, 3, 'V', 'AAV'), - 318: ('DEVSQ', 1, 30, 0x04, 1, 'V', 'R'), - 319: ('GEOMEAN', 1, 30, 0x04, 1, 'V', 'R'), - 320: ('HARMEAN', 1, 30, 0x04, 1, 'V', 'R'), - 321: ('SUMSQ', 0, 30, 0x04, 1, 'V', 'R'), - 322: ('KURT', 1, 30, 0x04, 1, 'V', 'R'), - 323: ('SKEW', 1, 30, 0x04, 1, 'V', 'R'), - 324: ('ZTEST', 2, 3, 0x04, 2, 'V', 'RV'), - 325: ('LARGE', 2, 2, 0x02, 2, 'V', 'RV'), - 326: ('SMALL', 2, 2, 0x02, 2, 'V', 'RV'), - 327: ('QUARTILE', 2, 2, 0x02, 2, 'V', 'RV'), - 328: ('PERCENTILE', 2, 2, 0x02, 2, 'V', 'RV'), - 329: ('PERCENTRANK', 2, 3, 0x04, 2, 'V', 'RV'), - 330: ('MODE', 1, 30, 0x04, 1, 'V', 'A'), - 331: ('TRIMMEAN', 2, 2, 0x02, 2, 'V', 'RV'), - 332: ('TINV', 2, 2, 0x02, 2, 'V', 'VV'), - 336: ('CONCATENATE', 0, 30, 0x04, 1, 'V', 'V'), - 337: ('POWER', 2, 2, 0x02, 2, 'V', 'VV'), - 342: ('RADIANS', 1, 1, 0x02, 1, 'V', 'V'), - 343: ('DEGREES', 1, 1, 0x02, 1, 'V', 'V'), - 344: ('SUBTOTAL', 2, 30, 0x04, 2, 'V', 'VR'), - 345: ('SUMIF', 2, 3, 0x04, 3, 'V', 'RVR'), - 346: ('COUNTIF', 2, 2, 0x02, 2, 'V', 'RV'), - 347: ('COUNTBLANK', 1, 1, 0x02, 1, 'V', 'R'), - 350: ('ISPMT', 4, 4, 0x02, 4, 'V', 'VVVV'), - 351: ('DATEDIF', 3, 3, 0x02, 3, 'V', 'VVV'), - 352: ('DATESTRING', 1, 1, 0x02, 1, 'V', 'V'), - 353: ('NUMBERSTRING', 2, 2, 0x02, 2, 'V', 'VV'), - 354: ('ROMAN', 1, 2, 0x04, 2, 'V', 'VV'), - 358: ('GETPIVOTDATA', 2, 2, 0x02, 2, 'V', 'RV'), - 359: ('HYPERLINK', 1, 2, 0x04, 2, 'V', 'VV'), - 360: ('PHONETIC', 1, 1, 0x02, 1, 'V', 'V'), - 361: ('AVERAGEA', 1, 30, 0x04, 1, 'V', 'R'), - 362: ('MAXA', 1, 30, 0x04, 1, 'V', 'R'), - 363: ('MINA', 1, 30, 0x04, 1, 'V', 'R'), - 364: ('STDEVPA', 1, 30, 0x04, 1, 'V', 'R'), - 365: ('VARPA', 1, 30, 0x04, 1, 'V', 'R'), - 366: ('STDEVA', 1, 30, 0x04, 1, 'V', 'R'), - 367: ('VARA', 1, 30, 0x04, 1, 'V', 'R'), - 368: ('BAHTTEXT', 1, 1, 0x02, 1, 'V', 'V'), - 369: ('THAIDAYOFWEEK', 1, 1, 0x02, 1, 'V', 'V'), - 370: ('THAIDIGIT', 1, 1, 0x02, 1, 'V', 'V'), - 371: ('THAIMONTHOFYEAR', 1, 1, 0x02, 1, 'V', 'V'), - 372: ('THAINUMSOUND', 1, 1, 0x02, 1, 'V', 'V'), - 373: ('THAINUMSTRING', 1, 1, 0x02, 1, 'V', 'V'), - 374: ('THAISTRINGLENGTH', 1, 1, 0x02, 1, 'V', 'V'), - 375: ('ISTHAIDIGIT', 1, 1, 0x02, 1, 'V', 'V'), - 376: ('ROUNDBAHTDOWN', 1, 1, 0x02, 1, 'V', 'V'), - 377: ('ROUNDBAHTUP', 1, 1, 0x02, 1, 'V', 'V'), - 378: ('THAIYEAR', 1, 1, 0x02, 1, 'V', 'V'), - 379: ('RTD', 2, 5, 0x04, 1, 'V', 'V'), - } - -tAttrNames = { - 0x00: "Skip??", # seen in SAMPLES.XLS which shipped with Excel 5.0 - 0x01: "Volatile", - 0x02: "If", - 0x04: "Choose", - 0x08: "Skip", - 0x10: "Sum", - 0x20: "Assign", - 0x40: "Space", - 0x41: "SpaceVolatile", - } - -error_opcodes = set([0x07, 0x08, 0x0A, 0x0B, 0x1C, 0x1D, 0x2F]) - -tRangeFuncs = (min, max, min, max, min, max) -tIsectFuncs = (max, min, max, min, max, min) - -def do_box_funcs(box_funcs, boxa, boxb): - return tuple([ - func(numa, numb) - for func, numa, numb in zip(box_funcs, boxa.coords, boxb.coords) - ]) - -def adjust_cell_addr_biff8(rowval, colval, reldelta, browx=None, bcolx=None): - row_rel = (colval >> 15) & 1 - col_rel = (colval >> 14) & 1 - rowx = rowval - colx = colval & 0xff - if reldelta: - if row_rel and rowx >= 32768: - rowx -= 65536 - if col_rel and colx >= 128: - colx -= 256 - else: - if row_rel: - rowx -= browx - if col_rel: - colx -= bcolx - return rowx, colx, row_rel, col_rel - -def adjust_cell_addr_biff_le7( - rowval, colval, reldelta, browx=None, bcolx=None): - row_rel = (rowval >> 15) & 1 - col_rel = (rowval >> 14) & 1 - rowx = rowval & 0x3fff - colx = colval - if reldelta: - if row_rel and rowx >= 8192: - rowx -= 16384 - if col_rel and colx >= 128: - colx -= 256 - else: - if row_rel: - rowx -= browx - if col_rel: - colx -= bcolx - return rowx, colx, row_rel, col_rel - -def get_cell_addr(data, pos, bv, reldelta, browx=None, bcolx=None): - if bv >= 80: - rowval, colval = unpack("= 80: - row1val, row2val, col1val, col2val = unpack(" addins %r" % (refx, info), file=bk.logfile) - assert ref_first_sheetx == 0xFFFE == ref_last_sheetx - return (-5, -5) - if ref_recordx != bk._supbook_locals_inx: - if blah: - print("/// get_externsheet_local_range(refx=%d) -> external %r" % (refx, info), file=bk.logfile) - return (-4, -4) # external reference - if ref_first_sheetx == 0xFFFE == ref_last_sheetx: - if blah: - print("/// get_externsheet_local_range(refx=%d) -> unspecified sheet %r" % (refx, info), file=bk.logfile) - return (-1, -1) # internal reference, any sheet - if ref_first_sheetx == 0xFFFF == ref_last_sheetx: - if blah: - print("/// get_externsheet_local_range(refx=%d) -> deleted sheet(s)" % (refx, ), file=bk.logfile) - return (-2, -2) # internal reference, deleted sheet(s) - nsheets = len(bk._all_sheets_map) - if not(0 <= ref_first_sheetx <= ref_last_sheetx < nsheets): - if blah: - print("/// get_externsheet_local_range(refx=%d) -> %r" % (refx, info), file=bk.logfile) - print("--- first/last sheet not in range(%d)" % nsheets, file=bk.logfile) - return (-102, -102) # stuffed up somewhere :-( - xlrd_sheetx1 = bk._all_sheets_map[ref_first_sheetx] - xlrd_sheetx2 = bk._all_sheets_map[ref_last_sheetx] - if not(0 <= xlrd_sheetx1 <= xlrd_sheetx2): - return (-3, -3) # internal reference, but to a macro sheet - return xlrd_sheetx1, xlrd_sheetx2 - -def get_externsheet_local_range_b57( - bk, raw_extshtx, ref_first_sheetx, ref_last_sheetx, blah=0): - if raw_extshtx > 0: - if blah: - print("/// get_externsheet_local_range_b57(raw_extshtx=%d) -> external" % raw_extshtx, file=bk.logfile) - return (-4, -4) # external reference - if ref_first_sheetx == -1 and ref_last_sheetx == -1: - return (-2, -2) # internal reference, deleted sheet(s) - nsheets = len(bk._all_sheets_map) - if not(0 <= ref_first_sheetx <= ref_last_sheetx < nsheets): - if blah: - print("/// get_externsheet_local_range_b57(%d, %d, %d) -> ???" \ - % (raw_extshtx, ref_first_sheetx, ref_last_sheetx), file=bk.logfile) - print("--- first/last sheet not in range(%d)" % nsheets, file=bk.logfile) - return (-103, -103) # stuffed up somewhere :-( - xlrd_sheetx1 = bk._all_sheets_map[ref_first_sheetx] - xlrd_sheetx2 = bk._all_sheets_map[ref_last_sheetx] - if not(0 <= xlrd_sheetx1 <= xlrd_sheetx2): - return (-3, -3) # internal reference, but to a macro sheet - return xlrd_sheetx1, xlrd_sheetx2 - -class FormulaError(Exception): - pass - - -## -# Used in evaluating formulas. -# The following table describes the kinds and how their values -# are represented.

    -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -#
    Kind symbolKind numberValue representation
    oBOOL3integer: 0 => False; 1 => True
    oERR4None, or an int error code (same as XL_CELL_ERROR in the Cell class). -#
    oMSNG5Used by Excel as a placeholder for a missing (not supplied) function -# argument. Should *not* appear as a final formula result. Value is None.
    oNUM2A float. Note that there is no way of distinguishing dates.
    oREF-1The value is either None or a non-empty list of -# absolute Ref3D instances.
    -#
    oREL-2The value is None or a non-empty list of -# fully or partially relative Ref3D instances. -#
    oSTRG1A Unicode string.
    oUNK0The kind is unknown or ambiguous. The value is None
    -#

    - -class Operand(object): - - ## - # None means that the actual value of the operand is a variable - # (depends on cell data), not a constant. - value = None - ## - # oUNK means that the kind of operand is not known unambiguously. - kind = oUNK - ## - # The reconstituted text of the original formula. Function names will be - # in English irrespective of the original language, which doesn't seem - # to be recorded anywhere. The separator is ",", not ";" or whatever else - # might be more appropriate for the end-user's locale; patches welcome. - text = '?' - - def __init__(self, akind=None, avalue=None, arank=0, atext='?'): - if akind is not None: - self.kind = akind - if avalue is not None: - self.value = avalue - self.rank = arank - # rank is an internal gizmo (operator precedence); - # it's used in reconstructing formula text. - self.text = atext - - def __repr__(self): - kind_text = okind_dict.get(self.kind, "?Unknown kind?") - return "Operand(kind=%s, value=%r, text=%r)" \ - % (kind_text, self.value, self.text) - -## -#

    Represents an absolute or relative 3-dimensional reference to a box -# of one or more cells.
    -# -- New in version 0.6.0 -#

    -# -#

    The coords attribute is a tuple of the form:
    -# (shtxlo, shtxhi, rowxlo, rowxhi, colxlo, colxhi)
    -# where 0 <= thingxlo <= thingx < thingxhi.
    -# Note that it is quite possible to have thingx > nthings; for example -# Print_Titles could have colxhi == 256 and/or rowxhi == 65536 -# irrespective of how many columns/rows are actually used in the worksheet. -# The caller will need to decide how to handle this situation. -# Keyword: IndexError :-) -#

    -# -#

    The components of the coords attribute are also available as individual -# attributes: shtxlo, shtxhi, rowxlo, rowxhi, colxlo, and colxhi.

    -# -#

    The relflags attribute is a 6-tuple of flags which indicate whether -# the corresponding (sheet|row|col)(lo|hi) is relative (1) or absolute (0).
    -# Note that there is necessarily no information available as to what cell(s) -# the reference could possibly be relative to. The caller must decide what if -# any use to make of oREL operands. Note also that a partially relative -# reference may well be a typo. -# For example, define name A1Z10 as $a$1:$z10 (missing $ after z) -# while the cursor is on cell Sheet3!A27.
    -# The resulting Ref3D instance will have coords = (2, 3, 0, -16, 0, 26) -# and relflags = (0, 0, 0, 1, 0, 0).
    -# So far, only one possibility of a sheet-relative component in -# a reference has been noticed: a 2D reference located in the "current sheet". -#
    This will appear as coords = (0, 1, ...) and relflags = (1, 1, ...). - -class Ref3D(tuple): - - def __init__(self, atuple): - self.coords = atuple[0:6] - self.relflags = atuple[6:12] - if not self.relflags: - self.relflags = (0, 0, 0, 0, 0, 0) - (self.shtxlo, self.shtxhi, - self.rowxlo, self.rowxhi, - self.colxlo, self.colxhi) = self.coords - - def __repr__(self): - if not self.relflags or self.relflags == (0, 0, 0, 0, 0, 0): - return "Ref3D(coords=%r)" % (self.coords, ) - else: - return "Ref3D(coords=%r, relflags=%r)" \ - % (self.coords, self.relflags) - -tAdd = 0x03 -tSub = 0x04 -tMul = 0x05 -tDiv = 0x06 -tPower = 0x07 -tConcat = 0x08 -tLT, tLE, tEQ, tGE, tGT, tNE = range(0x09, 0x0F) - -import operator as opr - -def nop(x): - return x - -def _opr_pow(x, y): return x ** y - -def _opr_lt(x, y): return x < y -def _opr_le(x, y): return x <= y -def _opr_eq(x, y): return x == y -def _opr_ge(x, y): return x >= y -def _opr_gt(x, y): return x > y -def _opr_ne(x, y): return x != y - -def num2strg(num): - """Attempt to emulate Excel's default conversion - from number to string. - """ - s = str(num) - if s.endswith(".0"): - s = s[:-2] - return s - -_arith_argdict = {oNUM: nop, oSTRG: float} -_cmp_argdict = {oNUM: nop, oSTRG: nop} -# Seems no conversions done on relops; in Excel, "1" > 9 produces TRUE. -_strg_argdict = {oNUM:num2strg, oSTRG:nop} -binop_rules = { - tAdd: (_arith_argdict, oNUM, opr.add, 30, '+'), - tSub: (_arith_argdict, oNUM, opr.sub, 30, '-'), - tMul: (_arith_argdict, oNUM, opr.mul, 40, '*'), - tDiv: (_arith_argdict, oNUM, opr.truediv, 40, '/'), - tPower: (_arith_argdict, oNUM, _opr_pow, 50, '^',), - tConcat:(_strg_argdict, oSTRG, opr.add, 20, '&'), - tLT: (_cmp_argdict, oBOOL, _opr_lt, 10, '<'), - tLE: (_cmp_argdict, oBOOL, _opr_le, 10, '<='), - tEQ: (_cmp_argdict, oBOOL, _opr_eq, 10, '='), - tGE: (_cmp_argdict, oBOOL, _opr_ge, 10, '>='), - tGT: (_cmp_argdict, oBOOL, _opr_gt, 10, '>'), - tNE: (_cmp_argdict, oBOOL, _opr_ne, 10, '<>'), - } - -unop_rules = { - 0x13: (lambda x: -x, 70, '-', ''), # unary minus - 0x12: (lambda x: x, 70, '+', ''), # unary plus - 0x14: (lambda x: x / 100.0, 60, '', '%'),# percent - } - -LEAF_RANK = 90 -FUNC_RANK = 90 - -STACK_ALARM_LEVEL = 5 -STACK_PANIC_LEVEL = 10 - -def evaluate_name_formula(bk, nobj, namex, blah=0, level=0): - if level > STACK_ALARM_LEVEL: - blah = 1 - data = nobj.raw_formula - fmlalen = nobj.basic_formula_len - bv = bk.biff_version - reldelta = 1 # All defined name formulas use "Method B" [OOo docs] - if blah: - print("::: evaluate_name_formula %r %r %d %d %r level=%d" \ - % (namex, nobj.name, fmlalen, bv, data, level), file=bk.logfile) - hex_char_dump(data, 0, fmlalen, fout=bk.logfile) - if level > STACK_PANIC_LEVEL: - raise XLRDError("Excessive indirect references in NAME formula") - sztab = szdict[bv] - pos = 0 - stack = [] - any_rel = 0 - any_err = 0 - any_external = 0 - unk_opnd = Operand(oUNK, None) - error_opnd = Operand(oERR, None) - spush = stack.append - - def do_binop(opcd, stk): - assert len(stk) >= 2 - bop = stk.pop() - aop = stk.pop() - argdict, result_kind, func, rank, sym = binop_rules[opcd] - otext = ''.join([ - '('[:aop.rank < rank], - aop.text, - ')'[:aop.rank < rank], - sym, - '('[:bop.rank < rank], - bop.text, - ')'[:bop.rank < rank], - ]) - resop = Operand(result_kind, None, rank, otext) - try: - bconv = argdict[bop.kind] - aconv = argdict[aop.kind] - except KeyError: - stk.append(resop) - return - if bop.value is None or aop.value is None: - stk.append(resop) - return - bval = bconv(bop.value) - aval = aconv(aop.value) - result = func(aval, bval) - if result_kind == oBOOL: - result = 1 if result else 0 - resop.value = result - stk.append(resop) - - def do_unaryop(opcode, result_kind, stk): - assert len(stk) >= 1 - aop = stk.pop() - val = aop.value - func, rank, sym1, sym2 = unop_rules[opcode] - otext = ''.join([ - sym1, - '('[:aop.rank < rank], - aop.text, - ')'[:aop.rank < rank], - sym2, - ]) - if val is not None: - val = func(val) - stk.append(Operand(result_kind, val, rank, otext)) - - def not_in_name_formula(op_arg, oname_arg): - msg = "ERROR *** Token 0x%02x (%s) found in NAME formula" \ - % (op_arg, oname_arg) - raise FormulaError(msg) - - if fmlalen == 0: - stack = [unk_opnd] - - while 0 <= pos < fmlalen: - op = BYTES_ORD(data[pos]) - opcode = op & 0x1f - optype = (op & 0x60) >> 5 - if optype: - opx = opcode + 32 - else: - opx = opcode - oname = onames[opx] # + [" RVA"][optype] - sz = sztab[opx] - if blah: - print("Pos:%d Op:0x%02x Name:t%s Sz:%d opcode:%02xh optype:%02xh" \ - % (pos, op, oname, sz, opcode, optype), file=bk.logfile) - print("Stack =", stack, file=bk.logfile) - if sz == -2: - msg = 'ERROR *** Unexpected token 0x%02x ("%s"); biff_version=%d' \ - % (op, oname, bv) - raise FormulaError(msg) - if not optype: - if 0x00 <= opcode <= 0x02: # unk_opnd, tExp, tTbl - not_in_name_formula(op, oname) - elif 0x03 <= opcode <= 0x0E: - # Add, Sub, Mul, Div, Power - # tConcat - # tLT, ..., tNE - do_binop(opcode, stack) - elif opcode == 0x0F: # tIsect - if blah: print("tIsect pre", stack, file=bk.logfile) - assert len(stack) >= 2 - bop = stack.pop() - aop = stack.pop() - sym = ' ' - rank = 80 ########## check ####### - otext = ''.join([ - '('[:aop.rank < rank], - aop.text, - ')'[:aop.rank < rank], - sym, - '('[:bop.rank < rank], - bop.text, - ')'[:bop.rank < rank], - ]) - res = Operand(oREF) - res.text = otext - if bop.kind == oERR or aop.kind == oERR: - res.kind = oERR - elif bop.kind == oUNK or aop.kind == oUNK: - # This can happen with undefined - # (go search in the current sheet) labels. - # For example =Bob Sales - # Each label gets a NAME record with an empty formula (!) - # Evaluation of the tName token classifies it as oUNK - # res.kind = oREF - pass - elif bop.kind == oREF == aop.kind: - if aop.value is not None and bop.value is not None: - assert len(aop.value) == 1 - assert len(bop.value) == 1 - coords = do_box_funcs( - tIsectFuncs, aop.value[0], bop.value[0]) - res.value = [Ref3D(coords)] - elif bop.kind == oREL == aop.kind: - res.kind = oREL - if aop.value is not None and bop.value is not None: - assert len(aop.value) == 1 - assert len(bop.value) == 1 - coords = do_box_funcs( - tIsectFuncs, aop.value[0], bop.value[0]) - relfa = aop.value[0].relflags - relfb = bop.value[0].relflags - if relfa == relfb: - res.value = [Ref3D(coords + relfa)] - else: - pass - spush(res) - if blah: print("tIsect post", stack, file=bk.logfile) - elif opcode == 0x10: # tList - if blah: print("tList pre", stack, file=bk.logfile) - assert len(stack) >= 2 - bop = stack.pop() - aop = stack.pop() - sym = ',' - rank = 80 ########## check ####### - otext = ''.join([ - '('[:aop.rank < rank], - aop.text, - ')'[:aop.rank < rank], - sym, - '('[:bop.rank < rank], - bop.text, - ')'[:bop.rank < rank], - ]) - res = Operand(oREF, None, rank, otext) - if bop.kind == oERR or aop.kind == oERR: - res.kind = oERR - elif bop.kind in (oREF, oREL) and aop.kind in (oREF, oREL): - res.kind = oREF - if aop.kind == oREL or bop.kind == oREL: - res.kind = oREL - if aop.value is not None and bop.value is not None: - assert len(aop.value) >= 1 - assert len(bop.value) == 1 - res.value = aop.value + bop.value - else: - pass - spush(res) - if blah: print("tList post", stack, file=bk.logfile) - elif opcode == 0x11: # tRange - if blah: print("tRange pre", stack, file=bk.logfile) - assert len(stack) >= 2 - bop = stack.pop() - aop = stack.pop() - sym = ':' - rank = 80 ########## check ####### - otext = ''.join([ - '('[:aop.rank < rank], - aop.text, - ')'[:aop.rank < rank], - sym, - '('[:bop.rank < rank], - bop.text, - ')'[:bop.rank < rank], - ]) - res = Operand(oREF, None, rank, otext) - if bop.kind == oERR or aop.kind == oERR: - res = oERR - elif bop.kind == oREF == aop.kind: - if aop.value is not None and bop.value is not None: - assert len(aop.value) == 1 - assert len(bop.value) == 1 - coords = do_box_funcs( - tRangeFuncs, aop.value[0], bop.value[0]) - res.value = [Ref3D(coords)] - elif bop.kind == oREL == aop.kind: - res.kind = oREL - if aop.value is not None and bop.value is not None: - assert len(aop.value) == 1 - assert len(bop.value) == 1 - coords = do_box_funcs( - tRangeFuncs, aop.value[0], bop.value[0]) - relfa = aop.value[0].relflags - relfb = bop.value[0].relflags - if relfa == relfb: - res.value = [Ref3D(coords + relfa)] - else: - pass - spush(res) - if blah: print("tRange post", stack, file=bk.logfile) - elif 0x12 <= opcode <= 0x14: # tUplus, tUminus, tPercent - do_unaryop(opcode, oNUM, stack) - elif opcode == 0x15: # tParen - # source cosmetics - pass - elif opcode == 0x16: # tMissArg - spush(Operand(oMSNG, None, LEAF_RANK, '')) - elif opcode == 0x17: # tStr - if bv <= 70: - strg, newpos = unpack_string_update_pos( - data, pos+1, bk.encoding, lenlen=1) - else: - strg, newpos = unpack_unicode_update_pos( - data, pos+1, lenlen=1) - sz = newpos - pos - if blah: print(" sz=%d strg=%r" % (sz, strg), file=bk.logfile) - text = '"' + strg.replace('"', '""') + '"' - spush(Operand(oSTRG, strg, LEAF_RANK, text)) - elif opcode == 0x18: # tExtended - # new with BIFF 8 - assert bv >= 80 - # not in OOo docs - raise FormulaError("tExtended token not implemented") - elif opcode == 0x19: # tAttr - subop, nc = unpack("= 1 - aop = stack[-1] - otext = 'SUM(%s)' % aop.text - stack[-1] = Operand(oNUM, None, FUNC_RANK, otext) - else: - sz = 4 - if blah: - print(" subop=%02xh subname=t%s sz=%d nc=%02xh" \ - % (subop, subname, sz, nc), file=bk.logfile) - elif 0x1A <= opcode <= 0x1B: # tSheet, tEndSheet - assert bv < 50 - raise FormulaError("tSheet & tEndsheet tokens not implemented") - elif 0x1C <= opcode <= 0x1F: # tErr, tBool, tInt, tNum - inx = opcode - 0x1C - nb = [1, 1, 2, 8][inx] - kind = [oERR, oBOOL, oNUM, oNUM][inx] - value, = unpack("<" + "BBHd"[inx], data[pos+1:pos+1+nb]) - if inx == 2: # tInt - value = float(value) - text = str(value) - elif inx == 3: # tNum - text = str(value) - elif inx == 1: # tBool - text = ('FALSE', 'TRUE')[value] - else: - text = '"' +error_text_from_code[value] + '"' - spush(Operand(kind, value, LEAF_RANK, text)) - else: - raise FormulaError("Unhandled opcode: 0x%02x" % opcode) - if sz <= 0: - raise FormulaError("Size not set for opcode 0x%02x" % opcode) - pos += sz - continue - if opcode == 0x00: # tArray - spush(unk_opnd) - elif opcode == 0x01: # tFunc - nb = 1 + int(bv >= 40) - funcx = unpack("<" + " BH"[nb], data[pos+1:pos+1+nb])[0] - func_attrs = func_defs.get(funcx, None) - if not func_attrs: - print("*** formula/tFunc unknown FuncID:%d" \ - % funcx, file=bk.logfile) - spush(unk_opnd) - else: - func_name, nargs = func_attrs[:2] - if blah: - print(" FuncID=%d name=%s nargs=%d" \ - % (funcx, func_name, nargs), file=bk.logfile) - assert len(stack) >= nargs - if nargs: - argtext = listsep.join([arg.text for arg in stack[-nargs:]]) - otext = "%s(%s)" % (func_name, argtext) - del stack[-nargs:] - else: - otext = func_name + "()" - res = Operand(oUNK, None, FUNC_RANK, otext) - spush(res) - elif opcode == 0x02: #tFuncVar - nb = 1 + int(bv >= 40) - nargs, funcx = unpack("= nargs - assert len(stack) >= nargs - argtext = listsep.join([arg.text for arg in stack[-nargs:]]) - otext = "%s(%s)" % (func_name, argtext) - res = Operand(oUNK, None, FUNC_RANK, otext) - if funcx == 1: # IF - testarg = stack[-nargs] - if testarg.kind not in (oNUM, oBOOL): - if blah and testarg.kind != oUNK: - print("IF testarg kind?", file=bk.logfile) - elif testarg.value not in (0, 1): - if blah and testarg.value is not None: - print("IF testarg value?", file=bk.logfile) - else: - if nargs == 2 and not testarg.value: - # IF(FALSE, tv) => FALSE - res.kind, res.value = oBOOL, 0 - else: - respos = -nargs + 2 - int(testarg.value) - chosen = stack[respos] - if chosen.kind == oMSNG: - res.kind, res.value = oNUM, 0 - else: - res.kind, res.value = chosen.kind, chosen.value - if blah: - print("$$$$$$ IF => constant", file=bk.logfile) - elif funcx == 100: # CHOOSE - testarg = stack[-nargs] - if testarg.kind == oNUM: - if 1 <= testarg.value < nargs: - chosen = stack[-nargs + int(testarg.value)] - if chosen.kind == oMSNG: - res.kind, res.value = oNUM, 0 - else: - res.kind, res.value = chosen.kind, chosen.value - del stack[-nargs:] - spush(res) - elif opcode == 0x03: #tName - tgtnamex = unpack("> bk.logfile, " ", res - # spush(res) - elif opcode == 0x0D: #tAreaN - not_in_name_formula(op, oname) - # res = get_cell_range_addr(data, pos+1, bv, reldelta=1) - # # note *ALL* tAreaN usage has signed offset for relative addresses - # any_rel = 1 - # if blah: print >> bk.logfile, " ", res - elif opcode == 0x1A: # tRef3d - if bv >= 80: - res = get_cell_addr(data, pos+3, bv, reldelta) - refx = unpack("= 80: - res1, res2 = get_cell_range_addr(data, pos+3, bv, reldelta) - refx = unpack("= 80: - refx, tgtnamex = unpack(" 0: - refx -= 1 - elif refx < 0: - refx = -refx - 1 - else: - dodgy = 1 - if blah: - print(" origrefx=%d refx=%d tgtnamex=%d dodgy=%d" \ - % (origrefx, refx, tgtnamex, dodgy), file=bk.logfile) - if tgtnamex == namex: - if blah: print("!!!! Self-referential !!!!", file=bk.logfile) - dodgy = any_err = 1 - if not dodgy: - if bv >= 80: - shx1, shx2 = get_externsheet_local_range(bk, refx, blah) - elif origrefx > 0: - shx1, shx2 = (-4, -4) # external ref - else: - exty = bk._externsheet_type_b57[refx] - if exty == 4: # non-specific sheet in own doc't - shx1, shx2 = (-1, -1) # internal, any sheet - else: - shx1, shx2 = (-666, -666) - if dodgy or shx1 < -1: - otext = "<>" \ - % (tgtnamex, origrefx) - res = Operand(oUNK, None, LEAF_RANK, otext) - else: - tgtobj = bk.name_obj_list[tgtnamex] - if not tgtobj.evaluated: - ### recursive ### - evaluate_name_formula(bk, tgtobj, tgtnamex, blah, level+1) - if tgtobj.macro or tgtobj.binary \ - or tgtobj.any_err: - if blah: - tgtobj.dump( - bk.logfile, - header="!!! bad tgtobj !!!", - footer="------------------", - ) - res = Operand(oUNK, None) - any_err = any_err or tgtobj.macro or tgtobj.binary or tgtobj.any_err - any_rel = any_rel or tgtobj.any_rel - else: - assert len(tgtobj.stack) == 1 - res = copy.deepcopy(tgtobj.stack[0]) - res.rank = LEAF_RANK - if tgtobj.scope == -1: - res.text = tgtobj.name - else: - res.text = "%s!%s" \ - % (bk._sheet_names[tgtobj.scope], tgtobj.name) - if blah: - print(" tNameX: setting text to", repr(res.text), file=bk.logfile) - spush(res) - elif opcode in error_opcodes: - any_err = 1 - spush(error_opnd) - else: - if blah: - print("FORMULA: /// Not handled yet: t" + oname, file=bk.logfile) - any_err = 1 - if sz <= 0: - raise FormulaError("Fatal: token size is not positive") - pos += sz - any_rel = not not any_rel - if blah: - fprintf(bk.logfile, "End of formula. level=%d any_rel=%d any_err=%d stack=%r\n", - level, not not any_rel, any_err, stack) - if len(stack) >= 2: - print("*** Stack has unprocessed args", file=bk.logfile) - print(file=bk.logfile) - nobj.stack = stack - if len(stack) != 1: - nobj.result = None - else: - nobj.result = stack[0] - nobj.any_rel = any_rel - nobj.any_err = any_err - nobj.any_external = any_external - nobj.evaluated = 1 - -#### under construction ############################################################################# -def decompile_formula(bk, fmla, fmlalen, - fmlatype=None, browx=None, bcolx=None, - blah=0, level=0, r1c1=0): - if level > STACK_ALARM_LEVEL: - blah = 1 - reldelta = fmlatype in (FMLA_TYPE_SHARED, FMLA_TYPE_NAME, FMLA_TYPE_COND_FMT, FMLA_TYPE_DATA_VAL) - data = fmla - bv = bk.biff_version - if blah: - print("::: decompile_formula len=%d fmlatype=%r browx=%r bcolx=%r reldelta=%d %r level=%d" \ - % (fmlalen, fmlatype, browx, bcolx, reldelta, data, level), file=bk.logfile) - hex_char_dump(data, 0, fmlalen, fout=bk.logfile) - if level > STACK_PANIC_LEVEL: - raise XLRDError("Excessive indirect references in formula") - sztab = szdict[bv] - pos = 0 - stack = [] - any_rel = 0 - any_err = 0 - any_external = 0 - unk_opnd = Operand(oUNK, None) - error_opnd = Operand(oERR, None) - spush = stack.append - - def do_binop(opcd, stk): - assert len(stk) >= 2 - bop = stk.pop() - aop = stk.pop() - argdict, result_kind, func, rank, sym = binop_rules[opcd] - otext = ''.join([ - '('[:aop.rank < rank], - aop.text, - ')'[:aop.rank < rank], - sym, - '('[:bop.rank < rank], - bop.text, - ')'[:bop.rank < rank], - ]) - resop = Operand(result_kind, None, rank, otext) - stk.append(resop) - - def do_unaryop(opcode, result_kind, stk): - assert len(stk) >= 1 - aop = stk.pop() - func, rank, sym1, sym2 = unop_rules[opcode] - otext = ''.join([ - sym1, - '('[:aop.rank < rank], - aop.text, - ')'[:aop.rank < rank], - sym2, - ]) - stk.append(Operand(result_kind, None, rank, otext)) - - def unexpected_opcode(op_arg, oname_arg): - msg = "ERROR *** Unexpected token 0x%02x (%s) found in formula type %s" \ - % (op_arg, oname_arg, FMLA_TYPEDESCR_MAP[fmlatype]) - print(msg, file=bk.logfile) - # raise FormulaError(msg) - - if fmlalen == 0: - stack = [unk_opnd] - - while 0 <= pos < fmlalen: - op = BYTES_ORD(data[pos]) - opcode = op & 0x1f - optype = (op & 0x60) >> 5 - if optype: - opx = opcode + 32 - else: - opx = opcode - oname = onames[opx] # + [" RVA"][optype] - sz = sztab[opx] - if blah: - print("Pos:%d Op:0x%02x opname:t%s Sz:%d opcode:%02xh optype:%02xh" \ - % (pos, op, oname, sz, opcode, optype), file=bk.logfile) - print("Stack =", stack, file=bk.logfile) - if sz == -2: - msg = 'ERROR *** Unexpected token 0x%02x ("%s"); biff_version=%d' \ - % (op, oname, bv) - raise FormulaError(msg) - if _TOKEN_NOT_ALLOWED(opx, 0) & fmlatype: - unexpected_opcode(op, oname) - if not optype: - if opcode <= 0x01: # tExp - if bv >= 30: - fmt = '= 2 - bop = stack.pop() - aop = stack.pop() - sym = ' ' - rank = 80 ########## check ####### - otext = ''.join([ - '('[:aop.rank < rank], - aop.text, - ')'[:aop.rank < rank], - sym, - '('[:bop.rank < rank], - bop.text, - ')'[:bop.rank < rank], - ]) - res = Operand(oREF) - res.text = otext - if bop.kind == oERR or aop.kind == oERR: - res.kind = oERR - elif bop.kind == oUNK or aop.kind == oUNK: - # This can happen with undefined - # (go search in the current sheet) labels. - # For example =Bob Sales - # Each label gets a NAME record with an empty formula (!) - # Evaluation of the tName token classifies it as oUNK - # res.kind = oREF - pass - elif bop.kind == oREF == aop.kind: - pass - elif bop.kind == oREL == aop.kind: - res.kind = oREL - else: - pass - spush(res) - if blah: print("tIsect post", stack, file=bk.logfile) - elif opcode == 0x10: # tList - if blah: print("tList pre", stack, file=bk.logfile) - assert len(stack) >= 2 - bop = stack.pop() - aop = stack.pop() - sym = ',' - rank = 80 ########## check ####### - otext = ''.join([ - '('[:aop.rank < rank], - aop.text, - ')'[:aop.rank < rank], - sym, - '('[:bop.rank < rank], - bop.text, - ')'[:bop.rank < rank], - ]) - res = Operand(oREF, None, rank, otext) - if bop.kind == oERR or aop.kind == oERR: - res.kind = oERR - elif bop.kind in (oREF, oREL) and aop.kind in (oREF, oREL): - res.kind = oREF - if aop.kind == oREL or bop.kind == oREL: - res.kind = oREL - else: - pass - spush(res) - if blah: print("tList post", stack, file=bk.logfile) - elif opcode == 0x11: # tRange - if blah: print("tRange pre", stack, file=bk.logfile) - assert len(stack) >= 2 - bop = stack.pop() - aop = stack.pop() - sym = ':' - rank = 80 ########## check ####### - otext = ''.join([ - '('[:aop.rank < rank], - aop.text, - ')'[:aop.rank < rank], - sym, - '('[:bop.rank < rank], - bop.text, - ')'[:bop.rank < rank], - ]) - res = Operand(oREF, None, rank, otext) - if bop.kind == oERR or aop.kind == oERR: - res = oERR - elif bop.kind == oREF == aop.kind: - pass - else: - pass - spush(res) - if blah: print("tRange post", stack, file=bk.logfile) - elif 0x12 <= opcode <= 0x14: # tUplus, tUminus, tPercent - do_unaryop(opcode, oNUM, stack) - elif opcode == 0x15: # tParen - # source cosmetics - pass - elif opcode == 0x16: # tMissArg - spush(Operand(oMSNG, None, LEAF_RANK, '')) - elif opcode == 0x17: # tStr - if bv <= 70: - strg, newpos = unpack_string_update_pos( - data, pos+1, bk.encoding, lenlen=1) - else: - strg, newpos = unpack_unicode_update_pos( - data, pos+1, lenlen=1) - sz = newpos - pos - if blah: print(" sz=%d strg=%r" % (sz, strg), file=bk.logfile) - text = '"' + strg.replace('"', '""') + '"' - spush(Operand(oSTRG, None, LEAF_RANK, text)) - elif opcode == 0x18: # tExtended - # new with BIFF 8 - assert bv >= 80 - # not in OOo docs, don't even know how to determine its length - raise FormulaError("tExtended token not implemented") - elif opcode == 0x19: # tAttr - subop, nc = unpack("= 1 - aop = stack[-1] - otext = 'SUM(%s)' % aop.text - stack[-1] = Operand(oNUM, None, FUNC_RANK, otext) - else: - sz = 4 - if blah: - print(" subop=%02xh subname=t%s sz=%d nc=%02xh" \ - % (subop, subname, sz, nc), file=bk.logfile) - elif 0x1A <= opcode <= 0x1B: # tSheet, tEndSheet - assert bv < 50 - raise FormulaError("tSheet & tEndsheet tokens not implemented") - elif 0x1C <= opcode <= 0x1F: # tErr, tBool, tInt, tNum - inx = opcode - 0x1C - nb = [1, 1, 2, 8][inx] - kind = [oERR, oBOOL, oNUM, oNUM][inx] - value, = unpack("<" + "BBHd"[inx], data[pos+1:pos+1+nb]) - if inx == 2: # tInt - value = float(value) - text = str(value) - elif inx == 3: # tNum - text = str(value) - elif inx == 1: # tBool - text = ('FALSE', 'TRUE')[value] - else: - text = '"' +error_text_from_code[value] + '"' - spush(Operand(kind, None, LEAF_RANK, text)) - else: - raise FormulaError("Unhandled opcode: 0x%02x" % opcode) - if sz <= 0: - raise FormulaError("Size not set for opcode 0x%02x" % opcode) - pos += sz - continue - if opcode == 0x00: # tArray - spush(unk_opnd) - elif opcode == 0x01: # tFunc - nb = 1 + int(bv >= 40) - funcx = unpack("<" + " BH"[nb], data[pos+1:pos+1+nb])[0] - func_attrs = func_defs.get(funcx, None) - if not func_attrs: - print("*** formula/tFunc unknown FuncID:%d" % funcx, file=bk.logfile) - spush(unk_opnd) - else: - func_name, nargs = func_attrs[:2] - if blah: - print(" FuncID=%d name=%s nargs=%d" \ - % (funcx, func_name, nargs), file=bk.logfile) - assert len(stack) >= nargs - if nargs: - argtext = listsep.join([arg.text for arg in stack[-nargs:]]) - otext = "%s(%s)" % (func_name, argtext) - del stack[-nargs:] - else: - otext = func_name + "()" - res = Operand(oUNK, None, FUNC_RANK, otext) - spush(res) - elif opcode == 0x02: #tFuncVar - nb = 1 + int(bv >= 40) - nargs, funcx = unpack("= nargs - assert len(stack) >= nargs - argtext = listsep.join([arg.text for arg in stack[-nargs:]]) - otext = "%s(%s)" % (func_name, argtext) - res = Operand(oUNK, None, FUNC_RANK, otext) - del stack[-nargs:] - spush(res) - elif opcode == 0x03: #tName - tgtnamex = unpack("> bk.logfile, " ", res - res1, res2 = get_cell_range_addr( - data, pos+1, bv, reldelta, browx, bcolx) - if blah: print(" ", res1, res2, file=bk.logfile) - rowx1, colx1, row_rel1, col_rel1 = res1 - rowx2, colx2, row_rel2, col_rel2 = res2 - coords = (rowx1, rowx2+1, colx1, colx2+1) - relflags = (row_rel1, row_rel2, col_rel1, col_rel2) - if sum(relflags): # relative - okind = oREL - else: - okind = oREF - if blah: print(" ", coords, relflags, file=bk.logfile) - otext = rangename2drel(coords, relflags, browx, bcolx, r1c1) - res = Operand(okind, None, LEAF_RANK, otext) - spush(res) - elif opcode == 0x1A: # tRef3d - if bv >= 80: - res = get_cell_addr(data, pos+3, bv, reldelta, browx, bcolx) - refx = unpack("= 80: - res1, res2 = get_cell_range_addr(data, pos+3, bv, reldelta) - refx = unpack("= 80: - refx, tgtnamex = unpack(" 0: - refx -= 1 - elif refx < 0: - refx = -refx - 1 - else: - dodgy = 1 - if blah: - print(" origrefx=%d refx=%d tgtnamex=%d dodgy=%d" \ - % (origrefx, refx, tgtnamex, dodgy), file=bk.logfile) - # if tgtnamex == namex: - # if blah: print >> bk.logfile, "!!!! Self-referential !!!!" - # dodgy = any_err = 1 - if not dodgy: - if bv >= 80: - shx1, shx2 = get_externsheet_local_range(bk, refx, blah) - elif origrefx > 0: - shx1, shx2 = (-4, -4) # external ref - else: - exty = bk._externsheet_type_b57[refx] - if exty == 4: # non-specific sheet in own doc't - shx1, shx2 = (-1, -1) # internal, any sheet - else: - shx1, shx2 = (-666, -666) - okind = oUNK - ovalue = None - if shx1 == -5: # addin func name - okind = oSTRG - ovalue = bk.addin_func_names[tgtnamex] - otext = '"' + ovalue.replace('"', '""') + '"' - elif dodgy or shx1 < -1: - otext = "<>" \ - % (tgtnamex, origrefx) - else: - tgtobj = bk.name_obj_list[tgtnamex] - if tgtobj.scope == -1: - otext = tgtobj.name - else: - otext = "%s!%s" \ - % (bk._sheet_names[tgtobj.scope], tgtobj.name) - if blah: - print(" tNameX: setting text to", repr(res.text), file=bk.logfile) - res = Operand(okind, ovalue, LEAF_RANK, otext) - spush(res) - elif opcode in error_opcodes: - any_err = 1 - spush(error_opnd) - else: - if blah: - print("FORMULA: /// Not handled yet: t" + oname, file=bk.logfile) - any_err = 1 - if sz <= 0: - raise FormulaError("Fatal: token size is not positive") - pos += sz - any_rel = not not any_rel - if blah: - print("End of formula. level=%d any_rel=%d any_err=%d stack=%r" % \ - (level, not not any_rel, any_err, stack), file=bk.logfile) - if len(stack) >= 2: - print("*** Stack has unprocessed args", file=bk.logfile) - print(file=bk.logfile) - - if len(stack) != 1: - result = None - else: - result = stack[0].text - return result - -#### under deconstruction ### -def dump_formula(bk, data, fmlalen, bv, reldelta, blah=0, isname=0): - if blah: - print("dump_formula", fmlalen, bv, len(data), file=bk.logfile) - hex_char_dump(data, 0, fmlalen, fout=bk.logfile) - assert bv >= 80 #### this function needs updating #### - sztab = szdict[bv] - pos = 0 - stack = [] - any_rel = 0 - any_err = 0 - spush = stack.append - while 0 <= pos < fmlalen: - op = BYTES_ORD(data[pos]) - opcode = op & 0x1f - optype = (op & 0x60) >> 5 - if optype: - opx = opcode + 32 - else: - opx = opcode - oname = onames[opx] # + [" RVA"][optype] - - sz = sztab[opx] - if blah: - print("Pos:%d Op:0x%02x Name:t%s Sz:%d opcode:%02xh optype:%02xh" \ - % (pos, op, oname, sz, opcode, optype), file=bk.logfile) - if not optype: - if 0x01 <= opcode <= 0x02: # tExp, tTbl - # reference to a shared formula or table record - rowx, colx = unpack("= 2 - bop = stack.pop() - aop = stack.pop() - spush(aop + bop) - if blah: print("tlist post", stack, file=bk.logfile) - elif opcode == 0x11: # tRange - if blah: print("tRange pre", stack, file=bk.logfile) - assert len(stack) >= 2 - bop = stack.pop() - aop = stack.pop() - assert len(aop) == 1 - assert len(bop) == 1 - result = do_box_funcs(tRangeFuncs, aop[0], bop[0]) - spush(result) - if blah: print("tRange post", stack, file=bk.logfile) - elif opcode == 0x0F: # tIsect - if blah: print("tIsect pre", stack, file=bk.logfile) - assert len(stack) >= 2 - bop = stack.pop() - aop = stack.pop() - assert len(aop) == 1 - assert len(bop) == 1 - result = do_box_funcs(tIsectFuncs, aop[0], bop[0]) - spush(result) - if blah: print("tIsect post", stack, file=bk.logfile) - elif opcode == 0x19: # tAttr - subop, nc = unpack("= 40) - funcx = unpack("<" + " BH"[nb], data[pos+1:pos+1+nb]) - if blah: print(" FuncID=%d" % funcx, file=bk.logfile) - elif opcode == 0x02: #tFuncVar - nb = 1 + int(bv >= 40) - nargs, funcx = unpack("= 2: - print("*** Stack has unprocessed args", file=bk.logfile) - -# === Some helper functions for displaying cell references === - -# I'm aware of only one possibility of a sheet-relative component in -# a reference: a 2D reference located in the "current sheet". -# xlrd stores this internally with bounds of (0, 1, ...) and -# relative flags of (1, 1, ...). These functions display the -# sheet component as empty, just like Excel etc. - -def rownamerel(rowx, rowxrel, browx=None, r1c1=0): - # if no base rowx is provided, we have to return r1c1 - if browx is None: - r1c1 = True - if not rowxrel: - if r1c1: - return "R%d" % (rowx+1) - return "$%d" % (rowx+1) - if r1c1: - if rowx: - return "R[%d]" % rowx - return "R" - return "%d" % ((browx + rowx) % 65536 + 1) - -def colnamerel(colx, colxrel, bcolx=None, r1c1=0): - # if no base colx is provided, we have to return r1c1 - if bcolx is None: - r1c1 = True - if not colxrel: - if r1c1: - return "C%d" % (colx + 1) - return "$" + colname(colx) - if r1c1: - if colx: - return "C[%d]" % colx - return "C" - return colname((bcolx + colx) % 256) - -## -# Utility function: (5, 7) => 'H6' -def cellname(rowx, colx): - """ (5, 7) => 'H6' """ - return "%s%d" % (colname(colx), rowx+1) - -## -# Utility function: (5, 7) => '$H$6' -def cellnameabs(rowx, colx, r1c1=0): - """ (5, 7) => '$H$6' or 'R8C6'""" - if r1c1: - return "R%dC%d" % (rowx+1, colx+1) - return "$%s$%d" % (colname(colx), rowx+1) - -def cellnamerel(rowx, colx, rowxrel, colxrel, browx=None, bcolx=None, r1c1=0): - if not rowxrel and not colxrel: - return cellnameabs(rowx, colx, r1c1) - if (rowxrel and browx is None) or (colxrel and bcolx is None): - # must flip the whole cell into R1C1 mode - r1c1 = True - c = colnamerel(colx, colxrel, bcolx, r1c1) - r = rownamerel(rowx, rowxrel, browx, r1c1) - if r1c1: - return r + c - return c + r - -## -# Utility function: 7 => 'H', 27 => 'AB' -def colname(colx): - """ 7 => 'H', 27 => 'AB' """ - alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - if colx <= 25: - return alphabet[colx] - else: - xdiv26, xmod26 = divmod(colx, 26) - return alphabet[xdiv26 - 1] + alphabet[xmod26] - -def rangename2d(rlo, rhi, clo, chi, r1c1=0): - """ (5, 20, 7, 10) => '$H$6:$J$20' """ - if r1c1: - return - if rhi == rlo+1 and chi == clo+1: - return cellnameabs(rlo, clo, r1c1) - return "%s:%s" % (cellnameabs(rlo, clo, r1c1), cellnameabs(rhi-1, chi-1, r1c1)) - -def rangename2drel(rlo_rhi_clo_chi, rlorel_rhirel_clorel_chirel, browx=None, bcolx=None, r1c1=0): - rlo, rhi, clo, chi = rlo_rhi_clo_chi - rlorel, rhirel, clorel, chirel = rlorel_rhirel_clorel_chirel - if (rlorel or rhirel) and browx is None: - r1c1 = True - if (clorel or chirel) and bcolx is None: - r1c1 = True - return "%s:%s" % ( - cellnamerel(rlo, clo, rlorel, clorel, browx, bcolx, r1c1), - cellnamerel(rhi-1, chi-1, rhirel, chirel, browx, bcolx, r1c1) - ) -## -# Utility function: -#
    Ref3D((1, 4, 5, 20, 7, 10)) => 'Sheet2:Sheet3!$H$6:$J$20' -def rangename3d(book, ref3d): - """ Ref3D(1, 4, 5, 20, 7, 10) => 'Sheet2:Sheet3!$H$6:$J$20' - (assuming Excel's default sheetnames) """ - coords = ref3d.coords - return "%s!%s" % ( - sheetrange(book, *coords[:2]), - rangename2d(*coords[2:6])) - -## -# Utility function: -#
    Ref3D(coords=(0, 1, -32, -22, -13, 13), relflags=(0, 0, 1, 1, 1, 1)) -# R1C1 mode => 'Sheet1!R[-32]C[-13]:R[-23]C[12]' -# A1 mode => depends on base cell (browx, bcolx) -def rangename3drel(book, ref3d, browx=None, bcolx=None, r1c1=0): - coords = ref3d.coords - relflags = ref3d.relflags - shdesc = sheetrangerel(book, coords[:2], relflags[:2]) - rngdesc = rangename2drel(coords[2:6], relflags[2:6], browx, bcolx, r1c1) - if not shdesc: - return rngdesc - return "%s!%s" % (shdesc, rngdesc) - -def quotedsheetname(shnames, shx): - if shx >= 0: - shname = shnames[shx] - else: - shname = { - -1: "?internal; any sheet?", - -2: "internal; deleted sheet", - -3: "internal; macro sheet", - -4: "<>", - }.get(shx, "?error %d?" % shx) - if "'" in shname: - return "'" + shname.replace("'", "''") + "'" - if " " in shname: - return "'" + shname + "'" - return shname - -def sheetrange(book, slo, shi): - shnames = book.sheet_names() - shdesc = quotedsheetname(shnames, slo) - if slo != shi-1: - shdesc += ":" + quotedsheetname(shnames, shi-1) - return shdesc - -def sheetrangerel(book, srange, srangerel): - slo, shi = srange - slorel, shirel = srangerel - if not slorel and not shirel: - return sheetrange(book, slo, shi) - assert (slo == 0 == shi-1) and slorel and shirel - return "" - -# ============================================================== diff --git a/webhub/xlrd/formula.pyc b/webhub/xlrd/formula.pyc deleted file mode 100644 index 404e2698..00000000 Binary files a/webhub/xlrd/formula.pyc and /dev/null differ diff --git a/webhub/xlrd/info.py b/webhub/xlrd/info.py deleted file mode 100644 index 528a2b4b..00000000 --- a/webhub/xlrd/info.py +++ /dev/null @@ -1 +0,0 @@ -__VERSION__ = "0.9.3" diff --git a/webhub/xlrd/info.pyc b/webhub/xlrd/info.pyc deleted file mode 100644 index 9a977e7c..00000000 Binary files a/webhub/xlrd/info.pyc and /dev/null differ diff --git a/webhub/xlrd/licences.py b/webhub/xlrd/licences.py deleted file mode 100644 index 1e262a97..00000000 --- a/webhub/xlrd/licences.py +++ /dev/null @@ -1,77 +0,0 @@ -# -*- coding: cp1252 -*- - -""" -Portions copyright 2005-2009, Stephen John Machin, Lingfo Pty Ltd -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -3. None of the names of Stephen John Machin, Lingfo Pty Ltd and any -contributors may be used to endorse or promote products derived from this -software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -THE POSSIBILITY OF SUCH DAMAGE. -""" - -""" -/*- - * Copyright (c) 2001 David Giffin. - * All rights reserved. - * - * Based on the the Java version: Andrew Khan Copyright (c) 2000. - * - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by - * David Giffin ." - * - * 4. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * David Giffin ." - * - * THIS SOFTWARE IS PROVIDED BY DAVID GIFFIN ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID GIFFIN OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ -""" diff --git a/webhub/xlrd/licences.pyc b/webhub/xlrd/licences.pyc deleted file mode 100644 index 91a930bd..00000000 Binary files a/webhub/xlrd/licences.pyc and /dev/null differ diff --git a/webhub/xlrd/sheet.py b/webhub/xlrd/sheet.py deleted file mode 100644 index 36438a09..00000000 --- a/webhub/xlrd/sheet.py +++ /dev/null @@ -1,2419 +0,0 @@ -# -*- coding: cp1252 -*- - -## -#

    Portions copyright 2005-2013 Stephen John Machin, Lingfo Pty Ltd

    -#

    This module is part of the xlrd package, which is released under a BSD-style licence.

    -## - -# 2010-04-25 SJM fix zoom factors cooking logic -# 2010-04-15 CW r4253 fix zoom factors cooking logic -# 2010-04-09 CW r4248 add a flag so xlutils knows whether or not to write a PANE record -# 2010-03-29 SJM Fixed bug in adding new empty rows in put_cell_ragged -# 2010-03-28 SJM Tailored put_cell method for each of ragged_rows=False (fixed speed regression) and =True (faster) -# 2010-03-25 CW r4236 Slight refactoring to remove method calls -# 2010-03-25 CW r4235 Collapse expand_cells into put_cell and enhance the raggedness. This should save even more memory! -# 2010-03-25 CW r4234 remove duplicate chunks for extend_cells; refactor to remove put_number_cell and put_blank_cell which essentially duplicated the code of put_cell -# 2010-03-10 SJM r4222 Added reading of the PANE record. -# 2010-03-10 SJM r4221 Preliminary work on "cooked" mag factors; use at own peril -# 2010-03-01 SJM Reading SCL record -# 2010-03-01 SJM Added ragged_rows functionality -# 2009-08-23 SJM Reduced CPU time taken by parsing MULBLANK records. -# 2009-08-18 SJM Used __slots__ and sharing to reduce memory consumed by Rowinfo instances -# 2009-05-31 SJM Fixed problem with no CODEPAGE record on extremely minimal BIFF2.x 3rd-party file -# 2009-04-27 SJM Integrated on_demand patch by Armando Serrano Lombillo -# 2008-02-09 SJM Excel 2.0: build XFs on the fly from cell attributes -# 2007-12-04 SJM Added support for Excel 2.x (BIFF2) files. -# 2007-10-11 SJM Added missing entry for blank cell type to ctype_text -# 2007-07-11 SJM Allow for BIFF2/3-style FORMAT record in BIFF4/8 file -# 2007-04-22 SJM Remove experimental "trimming" facility. - -from __future__ import print_function - -from array import array -from struct import unpack, calcsize -from .biffh import * -from .timemachine import * -from .formula import dump_formula, decompile_formula, rangename2d, FMLA_TYPE_CELL, FMLA_TYPE_SHARED -from .formatting import nearest_colour_index, Format - -DEBUG = 0 -OBJ_MSO_DEBUG = 0 - -_WINDOW2_options = ( - # Attribute names and initial values to use in case - # a WINDOW2 record is not written. - ("show_formulas", 0), - ("show_grid_lines", 1), - ("show_sheet_headers", 1), - ("panes_are_frozen", 0), - ("show_zero_values", 1), - ("automatic_grid_line_colour", 1), - ("columns_from_right_to_left", 0), - ("show_outline_symbols", 1), - ("remove_splits_if_pane_freeze_is_removed", 0), - # Multiple sheets can be selected, but only one can be active - # (hold down Ctrl and click multiple tabs in the file in OOo) - ("sheet_selected", 0), - # "sheet_visible" should really be called "sheet_active" - # and is 1 when this sheet is the sheet displayed when the file - # is open. More than likely only one sheet should ever be set as - # visible. - # This would correspond to the Book's sheet_active attribute, but - # that doesn't exist as WINDOW1 records aren't currently processed. - # The real thing is the visibility attribute from the BOUNDSHEET record. - ("sheet_visible", 0), - ("show_in_page_break_preview", 0), - ) - -## -#

    Contains the data for one worksheet.

    -# -#

    In the cell access functions, "rowx" is a row index, counting from zero, and "colx" is a -# column index, counting from zero. -# Negative values for row/column indexes and slice positions are supported in the expected fashion.

    -# -#

    For information about cell types and cell values, refer to the documentation of the {@link #Cell} class.

    -# -#

    WARNING: You don't call this class yourself. You access Sheet objects via the Book object that -# was returned when you called xlrd.open_workbook("myfile.xls").

    - - -class Sheet(BaseObject): - ## - # Name of sheet. - name = '' - - ## - # A reference to the Book object to which this sheet belongs. - # Example usage: some_sheet.book.datemode - book = None - - ## - # Number of rows in sheet. A row index is in range(thesheet.nrows). - nrows = 0 - - ## - # Nominal number of columns in sheet. It is 1 + the maximum column index - # found, ignoring trailing empty cells. See also open_workbook(ragged_rows=?) - # and Sheet.{@link #Sheet.row_len}(row_index). - ncols = 0 - - ## - # The map from a column index to a {@link #Colinfo} object. Often there is an entry - # in COLINFO records for all column indexes in range(257). - # Note that xlrd ignores the entry for the non-existent - # 257th column. On the other hand, there may be no entry for unused columns. - #
    -- New in version 0.6.1. Populated only if open_workbook(formatting_info=True). - colinfo_map = {} - - ## - # The map from a row index to a {@link #Rowinfo} object. Note that it is possible - # to have missing entries -- at least one source of XLS files doesn't - # bother writing ROW records. - #
    -- New in version 0.6.1. Populated only if open_workbook(formatting_info=True). - rowinfo_map = {} - - ## - # List of address ranges of cells containing column labels. - # These are set up in Excel by Insert > Name > Labels > Columns. - #
    -- New in version 0.6.0 - #
    How to deconstruct the list: - #
    -    # for crange in thesheet.col_label_ranges:
    -    #     rlo, rhi, clo, chi = crange
    -    #     for rx in xrange(rlo, rhi):
    -    #         for cx in xrange(clo, chi):
    -    #             print "Column label at (rowx=%d, colx=%d) is %r" \
    -    #                 (rx, cx, thesheet.cell_value(rx, cx))
    -    # 
    - col_label_ranges = [] - - ## - # List of address ranges of cells containing row labels. - # For more details, see col_label_ranges above. - #
    -- New in version 0.6.0 - row_label_ranges = [] - - ## - # List of address ranges of cells which have been merged. - # These are set up in Excel by Format > Cells > Alignment, then ticking - # the "Merge cells" box. - #
    -- New in version 0.6.1. Extracted only if open_workbook(formatting_info=True). - #
    How to deconstruct the list: - #
    -    # for crange in thesheet.merged_cells:
    -    #     rlo, rhi, clo, chi = crange
    -    #     for rowx in xrange(rlo, rhi):
    -    #         for colx in xrange(clo, chi):
    -    #             # cell (rlo, clo) (the top left one) will carry the data
    -    #             # and formatting info; the remainder will be recorded as
    -    #             # blank cells, but a renderer will apply the formatting info
    -    #             # for the top left cell (e.g. border, pattern) to all cells in
    -    #             # the range.
    -    # 
    - merged_cells = [] - - ## - # Mapping of (rowx, colx) to list of (offset, font_index) tuples. The offset - # defines where in the string the font begins to be used. - # Offsets are expected to be in ascending order. - # If the first offset is not zero, the meaning is that the cell's XF's font should - # be used from offset 0. - #
    This is a sparse mapping. There is no entry for cells that are not formatted with - # rich text. - #
    How to use: - #
    -    # runlist = thesheet.rich_text_runlist_map.get((rowx, colx))
    -    # if runlist:
    -    #     for offset, font_index in runlist:
    -    #         # do work here.
    -    #         pass
    -    # 
    - # Populated only if open_workbook(formatting_info=True). - #
    -- New in version 0.7.2. - #
      - rich_text_runlist_map = {} - - ## - # Default column width from DEFCOLWIDTH record, else None. - # From the OOo docs:
    - # """Column width in characters, using the width of the zero character - # from default font (first FONT record in the file). Excel adds some - # extra space to the default width, depending on the default font and - # default font size. The algorithm how to exactly calculate the resulting - # column width is not known.
    - # Example: The default width of 8 set in this record results in a column - # width of 8.43 using Arial font with a size of 10 points."""
    - # For the default hierarchy, refer to the {@link #Colinfo} class. - #
    -- New in version 0.6.1 - defcolwidth = None - - ## - # Default column width from STANDARDWIDTH record, else None. - # From the OOo docs:
    - # """Default width of the columns in 1/256 of the width of the zero - # character, using default font (first FONT record in the file)."""
    - # For the default hierarchy, refer to the {@link #Colinfo} class. - #
    -- New in version 0.6.1 - standardwidth = None - - ## - # Default value to be used for a row if there is - # no ROW record for that row. - # From the optional DEFAULTROWHEIGHT record. - default_row_height = None - - ## - # Default value to be used for a row if there is - # no ROW record for that row. - # From the optional DEFAULTROWHEIGHT record. - default_row_height_mismatch = None - - ## - # Default value to be used for a row if there is - # no ROW record for that row. - # From the optional DEFAULTROWHEIGHT record. - default_row_hidden = None - - ## - # Default value to be used for a row if there is - # no ROW record for that row. - # From the optional DEFAULTROWHEIGHT record. - default_additional_space_above = None - - ## - # Default value to be used for a row if there is - # no ROW record for that row. - # From the optional DEFAULTROWHEIGHT record. - default_additional_space_below = None - - ## - # Visibility of the sheet. 0 = visible, 1 = hidden (can be unhidden - # by user -- Format/Sheet/Unhide), 2 = "very hidden" (can be unhidden - # only by VBA macro). - visibility = 0 - - ## - # A 256-element tuple corresponding to the contents of the GCW record for this sheet. - # If no such record, treat as all bits zero. - # Applies to BIFF4-7 only. See docs of the {@link #Colinfo} class for discussion. - gcw = (0, ) * 256 - - ## - #

    A list of {@link #Hyperlink} objects corresponding to HLINK records found - # in the worksheet.
    -- New in version 0.7.2

    - hyperlink_list = [] - - ## - #

    A sparse mapping from (rowx, colx) to an item in {@link #Sheet.hyperlink_list}. - # Cells not covered by a hyperlink are not mapped. - # It is possible using the Excel UI to set up a hyperlink that - # covers a larger-than-1x1 rectangle of cells. - # Hyperlink rectangles may overlap (Excel doesn't check). - # When a multiply-covered cell is clicked on, the hyperlink that is activated - # (and the one that is mapped here) is the last in hyperlink_list. - #
    -- New in version 0.7.2

    - hyperlink_map = {} - - ## - #

    A sparse mapping from (rowx, colx) to a {@link #Note} object. - # Cells not containing a note ("comment") are not mapped. - #
    -- New in version 0.7.2

    - cell_note_map = {} - - ## - # Number of columns in left pane (frozen panes; for split panes, see comments below in code) - vert_split_pos = 0 - - ## - # Number of rows in top pane (frozen panes; for split panes, see comments below in code) - horz_split_pos = 0 - - ## - # Index of first visible row in bottom frozen/split pane - horz_split_first_visible = 0 - - ## - # Index of first visible column in right frozen/split pane - vert_split_first_visible = 0 - - ## - # Frozen panes: ignore it. Split panes: explanation and diagrams in OOo docs. - split_active_pane = 0 - - ## - # Boolean specifying if a PANE record was present, ignore unless you're xlutils.copy - has_pane_record = 0 - - ## - # A list of the horizontal page breaks in this sheet. - # Breaks are tuples in the form (index of row after break, start col index, end col index). - # Populated only if open_workbook(formatting_info=True). - #
    -- New in version 0.7.2 - horizontal_page_breaks = [] - - ## - # A list of the vertical page breaks in this sheet. - # Breaks are tuples in the form (index of col after break, start row index, end row index). - # Populated only if open_workbook(formatting_info=True). - #
    -- New in version 0.7.2 - vertical_page_breaks = [] - - - def __init__(self, book, position, name, number): - self.book = book - self.biff_version = book.biff_version - self._position = position - self.logfile = book.logfile - self.bt = array('B', [XL_CELL_EMPTY]) - self.bf = array('h', [-1]) - self.name = name - self.number = number - self.verbosity = book.verbosity - self.formatting_info = book.formatting_info - self.ragged_rows = book.ragged_rows - if self.ragged_rows: - self.put_cell = self.put_cell_ragged - else: - self.put_cell = self.put_cell_unragged - self._xf_index_to_xl_type_map = book._xf_index_to_xl_type_map - self.nrows = 0 # actual, including possibly empty cells - self.ncols = 0 - self._maxdatarowx = -1 # highest rowx containing a non-empty cell - self._maxdatacolx = -1 # highest colx containing a non-empty cell - self._dimnrows = 0 # as per DIMENSIONS record - self._dimncols = 0 - self._cell_values = [] - self._cell_types = [] - self._cell_xf_indexes = [] - self.defcolwidth = None - self.standardwidth = None - self.default_row_height = None - self.default_row_height_mismatch = 0 - self.default_row_hidden = 0 - self.default_additional_space_above = 0 - self.default_additional_space_below = 0 - self.colinfo_map = {} - self.rowinfo_map = {} - self.col_label_ranges = [] - self.row_label_ranges = [] - self.merged_cells = [] - self.rich_text_runlist_map = {} - self.horizontal_page_breaks = [] - self.vertical_page_breaks = [] - self._xf_index_stats = [0, 0, 0, 0] - self.visibility = book._sheet_visibility[number] # from BOUNDSHEET record - for attr, defval in _WINDOW2_options: - setattr(self, attr, defval) - self.first_visible_rowx = 0 - self.first_visible_colx = 0 - self.gridline_colour_index = 0x40 - self.gridline_colour_rgb = None # pre-BIFF8 - self.hyperlink_list = [] - self.hyperlink_map = {} - self.cell_note_map = {} - - # Values calculated by xlrd to predict the mag factors that - # will actually be used by Excel to display your worksheet. - # Pass these values to xlwt when writing XLS files. - # Warning 1: Behaviour of OOo Calc and Gnumeric has been observed to differ from Excel's. - # Warning 2: A value of zero means almost exactly what it says. Your sheet will be - # displayed as a very tiny speck on the screen. xlwt will reject attempts to set - # a mag_factor that is not (10 <= mag_factor <= 400). - self.cooked_page_break_preview_mag_factor = 60 - self.cooked_normal_view_mag_factor = 100 - - # Values (if any) actually stored on the XLS file - self.cached_page_break_preview_mag_factor = None # from WINDOW2 record - self.cached_normal_view_mag_factor = None # from WINDOW2 record - self.scl_mag_factor = None # from SCL record - - self._ixfe = None # BIFF2 only - self._cell_attr_to_xfx = {} # BIFF2.0 only - - #### Don't initialise this here, use class attribute initialisation. - #### self.gcw = (0, ) * 256 #### - - if self.biff_version >= 80: - self.utter_max_rows = 65536 - else: - self.utter_max_rows = 16384 - self.utter_max_cols = 256 - - self._first_full_rowx = -1 - - # self._put_cell_exceptions = 0 - # self._put_cell_row_widenings = 0 - # self._put_cell_rows_appended = 0 - # self._put_cell_cells_appended = 0 - - - ## - # {@link #Cell} object in the given row and column. - def cell(self, rowx, colx): - if self.formatting_info: - xfx = self.cell_xf_index(rowx, colx) - else: - xfx = None - return Cell( - self._cell_types[rowx][colx], - self._cell_values[rowx][colx], - xfx, - ) - - ## - # Value of the cell in the given row and column. - def cell_value(self, rowx, colx): - return self._cell_values[rowx][colx] - - ## - # Type of the cell in the given row and column. - # Refer to the documentation of the {@link #Cell} class. - def cell_type(self, rowx, colx): - return self._cell_types[rowx][colx] - - ## - # XF index of the cell in the given row and column. - # This is an index into Book.{@link #Book.xf_list}. - #
    -- New in version 0.6.1 - def cell_xf_index(self, rowx, colx): - self.req_fmt_info() - xfx = self._cell_xf_indexes[rowx][colx] - if xfx > -1: - self._xf_index_stats[0] += 1 - return xfx - # Check for a row xf_index - try: - xfx = self.rowinfo_map[rowx].xf_index - if xfx > -1: - self._xf_index_stats[1] += 1 - return xfx - except KeyError: - pass - # Check for a column xf_index - try: - xfx = self.colinfo_map[colx].xf_index - if xfx == -1: xfx = 15 - self._xf_index_stats[2] += 1 - return xfx - except KeyError: - # If all else fails, 15 is used as hardwired global default xf_index. - self._xf_index_stats[3] += 1 - return 15 - - ## - # Returns the effective number of cells in the given row. For use with - # open_workbook(ragged_rows=True) which is likely to produce rows - # with fewer than {@link #Sheet.ncols} cells. - #
    -- New in version 0.7.2 - def row_len(self, rowx): - return len(self._cell_values[rowx]) - - ## - # Returns a sequence of the {@link #Cell} objects in the given row. - def row(self, rowx): - return [ - self.cell(rowx, colx) - for colx in xrange(len(self._cell_values[rowx])) - ] - - ## - # Returns a slice of the types - # of the cells in the given row. - def row_types(self, rowx, start_colx=0, end_colx=None): - if end_colx is None: - return self._cell_types[rowx][start_colx:] - return self._cell_types[rowx][start_colx:end_colx] - - ## - # Returns a slice of the values - # of the cells in the given row. - def row_values(self, rowx, start_colx=0, end_colx=None): - if end_colx is None: - return self._cell_values[rowx][start_colx:] - return self._cell_values[rowx][start_colx:end_colx] - - ## - # Returns a slice of the {@link #Cell} objects in the given row. - def row_slice(self, rowx, start_colx=0, end_colx=None): - nc = len(self._cell_values[rowx]) - if start_colx < 0: - start_colx += nc - if start_colx < 0: - start_colx = 0 - if end_colx is None or end_colx > nc: - end_colx = nc - elif end_colx < 0: - end_colx += nc - return [ - self.cell(rowx, colx) - for colx in xrange(start_colx, end_colx) - ] - - ## - # Returns a slice of the {@link #Cell} objects in the given column. - def col_slice(self, colx, start_rowx=0, end_rowx=None): - nr = self.nrows - if start_rowx < 0: - start_rowx += nr - if start_rowx < 0: - start_rowx = 0 - if end_rowx is None or end_rowx > nr: - end_rowx = nr - elif end_rowx < 0: - end_rowx += nr - return [ - self.cell(rowx, colx) - for rowx in xrange(start_rowx, end_rowx) - ] - - ## - # Returns a slice of the values of the cells in the given column. - def col_values(self, colx, start_rowx=0, end_rowx=None): - nr = self.nrows - if start_rowx < 0: - start_rowx += nr - if start_rowx < 0: - start_rowx = 0 - if end_rowx is None or end_rowx > nr: - end_rowx = nr - elif end_rowx < 0: - end_rowx += nr - return [ - self._cell_values[rowx][colx] - for rowx in xrange(start_rowx, end_rowx) - ] - - ## - # Returns a slice of the types of the cells in the given column. - def col_types(self, colx, start_rowx=0, end_rowx=None): - nr = self.nrows - if start_rowx < 0: - start_rowx += nr - if start_rowx < 0: - start_rowx = 0 - if end_rowx is None or end_rowx > nr: - end_rowx = nr - elif end_rowx < 0: - end_rowx += nr - return [ - self._cell_types[rowx][colx] - for rowx in xrange(start_rowx, end_rowx) - ] - - ## - # Returns a sequence of the {@link #Cell} objects in the given column. - def col(self, colx): - return self.col_slice(colx) - # Above two lines just for the docs. Here's the real McCoy: - col = col_slice - - # === Following methods are used in building the worksheet. - # === They are not part of the API. - - def tidy_dimensions(self): - if self.verbosity >= 3: - fprintf(self.logfile, - "tidy_dimensions: nrows=%d ncols=%d \n", - self.nrows, self.ncols, - ) - if 1 and self.merged_cells: - nr = nc = 0 - umaxrows = self.utter_max_rows - umaxcols = self.utter_max_cols - for crange in self.merged_cells: - rlo, rhi, clo, chi = crange - if not (0 <= rlo < rhi <= umaxrows) \ - or not (0 <= clo < chi <= umaxcols): - fprintf(self.logfile, - "*** WARNING: sheet #%d (%r), MERGEDCELLS bad range %r\n", - self.number, self.name, crange) - if rhi > nr: nr = rhi - if chi > nc: nc = chi - if nc > self.ncols: - self.ncols = nc - if nr > self.nrows: - # we put one empty cell at (nr-1,0) to make sure - # we have the right number of rows. The ragged rows - # will sort out the rest if needed. - self.put_cell(nr-1, 0, XL_CELL_EMPTY, '', -1) - if self.verbosity >= 1 \ - and (self.nrows != self._dimnrows or self.ncols != self._dimncols): - fprintf(self.logfile, - "NOTE *** sheet %d (%r): DIMENSIONS R,C = %d,%d should be %d,%d\n", - self.number, - self.name, - self._dimnrows, - self._dimncols, - self.nrows, - self.ncols, - ) - if not self.ragged_rows: - # fix ragged rows - ncols = self.ncols - s_cell_types = self._cell_types - s_cell_values = self._cell_values - s_cell_xf_indexes = self._cell_xf_indexes - s_fmt_info = self.formatting_info - # for rowx in xrange(self.nrows): - if self._first_full_rowx == -2: - ubound = self.nrows - else: - ubound = self._first_full_rowx - for rowx in xrange(ubound): - trow = s_cell_types[rowx] - rlen = len(trow) - nextra = ncols - rlen - if nextra > 0: - s_cell_values[rowx][rlen:] = [''] * nextra - trow[rlen:] = self.bt * nextra - if s_fmt_info: - s_cell_xf_indexes[rowx][rlen:] = self.bf * nextra - - def put_cell_ragged(self, rowx, colx, ctype, value, xf_index): - if ctype is None: - # we have a number, so look up the cell type - ctype = self._xf_index_to_xl_type_map[xf_index] - assert 0 <= colx < self.utter_max_cols - assert 0 <= rowx < self.utter_max_rows - fmt_info = self.formatting_info - - try: - nr = rowx + 1 - if self.nrows < nr: - - scta = self._cell_types.append - scva = self._cell_values.append - scxa = self._cell_xf_indexes.append - bt = self.bt - bf = self.bf - for _unused in xrange(self.nrows, nr): - scta(bt * 0) - scva([]) - if fmt_info: - scxa(bf * 0) - self.nrows = nr - - types_row = self._cell_types[rowx] - values_row = self._cell_values[rowx] - if fmt_info: - fmt_row = self._cell_xf_indexes[rowx] - ltr = len(types_row) - if colx >= self.ncols: - self.ncols = colx + 1 - num_empty = colx - ltr - if not num_empty: - # most common case: colx == previous colx + 1 - # self._put_cell_cells_appended += 1 - types_row.append(ctype) - values_row.append(value) - if fmt_info: - fmt_row.append(xf_index) - return - if num_empty > 0: - num_empty += 1 - # self._put_cell_row_widenings += 1 - # types_row.extend(self.bt * num_empty) - # values_row.extend([''] * num_empty) - # if fmt_info: - # fmt_row.extend(self.bf * num_empty) - types_row[ltr:] = self.bt * num_empty - values_row[ltr:] = [''] * num_empty - if fmt_info: - fmt_row[ltr:] = self.bf * num_empty - types_row[colx] = ctype - values_row[colx] = value - if fmt_info: - fmt_row[colx] = xf_index - except: - print("put_cell", rowx, colx, file=self.logfile) - raise - - def put_cell_unragged(self, rowx, colx, ctype, value, xf_index): - if ctype is None: - # we have a number, so look up the cell type - ctype = self._xf_index_to_xl_type_map[xf_index] - # assert 0 <= colx < self.utter_max_cols - # assert 0 <= rowx < self.utter_max_rows - try: - self._cell_types[rowx][colx] = ctype - self._cell_values[rowx][colx] = value - if self.formatting_info: - self._cell_xf_indexes[rowx][colx] = xf_index - except IndexError: - # print >> self.logfile, "put_cell extending", rowx, colx - # self.extend_cells(rowx+1, colx+1) - # self._put_cell_exceptions += 1 - nr = rowx + 1 - nc = colx + 1 - assert 1 <= nc <= self.utter_max_cols - assert 1 <= nr <= self.utter_max_rows - if nc > self.ncols: - self.ncols = nc - # The row self._first_full_rowx and all subsequent rows - # are guaranteed to have length == self.ncols. Thus the - # "fix ragged rows" section of the tidy_dimensions method - # doesn't need to examine them. - if nr < self.nrows: - # cell data is not in non-descending row order *AND* - # self.ncols has been bumped up. - # This very rare case ruins this optmisation. - self._first_full_rowx = -2 - elif rowx > self._first_full_rowx > -2: - self._first_full_rowx = rowx - if nr <= self.nrows: - # New cell is in an existing row, so extend that row (if necessary). - # Note that nr < self.nrows means that the cell data - # is not in ascending row order!! - trow = self._cell_types[rowx] - nextra = self.ncols - len(trow) - if nextra > 0: - # self._put_cell_row_widenings += 1 - trow.extend(self.bt * nextra) - if self.formatting_info: - self._cell_xf_indexes[rowx].extend(self.bf * nextra) - self._cell_values[rowx].extend([''] * nextra) - else: - scta = self._cell_types.append - scva = self._cell_values.append - scxa = self._cell_xf_indexes.append - fmt_info = self.formatting_info - nc = self.ncols - bt = self.bt - bf = self.bf - for _unused in xrange(self.nrows, nr): - # self._put_cell_rows_appended += 1 - scta(bt * nc) - scva([''] * nc) - if fmt_info: - scxa(bf * nc) - self.nrows = nr - # === end of code from extend_cells() - try: - self._cell_types[rowx][colx] = ctype - self._cell_values[rowx][colx] = value - if self.formatting_info: - self._cell_xf_indexes[rowx][colx] = xf_index - except: - print("put_cell", rowx, colx, file=self.logfile) - raise - except: - print("put_cell", rowx, colx, file=self.logfile) - raise - - - # === Methods after this line neither know nor care about how cells are stored. - - def read(self, bk): - global rc_stats - DEBUG = 0 - blah = DEBUG or self.verbosity >= 2 - blah_rows = DEBUG or self.verbosity >= 4 - blah_formulas = 0 and blah - r1c1 = 0 - oldpos = bk._position - bk._position = self._position - XL_SHRFMLA_ETC_ETC = ( - XL_SHRFMLA, XL_ARRAY, XL_TABLEOP, XL_TABLEOP2, - XL_ARRAY2, XL_TABLEOP_B2, - ) - self_put_cell = self.put_cell - local_unpack = unpack - bk_get_record_parts = bk.get_record_parts - bv = self.biff_version - fmt_info = self.formatting_info - do_sst_rich_text = fmt_info and bk._rich_text_runlist_map - rowinfo_sharing_dict = {} - txos = {} - eof_found = 0 - while 1: - # if DEBUG: print "SHEET.READ: about to read from position %d" % bk._position - rc, data_len, data = bk_get_record_parts() - # if rc in rc_stats: - # rc_stats[rc] += 1 - # else: - # rc_stats[rc] = 1 - # if DEBUG: print "SHEET.READ: op 0x%04x, %d bytes %r" % (rc, data_len, data) - if rc == XL_NUMBER: - # [:14] in following stmt ignores extraneous rubbish at end of record. - # Sample file testEON-8.xls supplied by Jan Kraus. - rowx, colx, xf_index, d = local_unpack('> 15) & 1 - r.outline_level = bits2 & 7 - r.outline_group_starts_ends = (bits2 >> 4) & 1 - r.hidden = (bits2 >> 5) & 1 - r.height_mismatch = (bits2 >> 6) & 1 - r.has_default_xf_index = (bits2 >> 7) & 1 - r.xf_index = (bits2 >> 16) & 0xfff - r.additional_space_above = (bits2 >> 28) & 1 - r.additional_space_below = (bits2 >> 29) & 1 - if not r.has_default_xf_index: - r.xf_index = -1 - self.rowinfo_map[rowx] = r - if 0 and r.xf_index > -1: - fprintf(self.logfile, - "**ROW %d %d %d\n", - self.number, rowx, r.xf_index) - if blah_rows: - print('ROW', rowx, bits1, bits2, file=self.logfile) - r.dump(self.logfile, - header="--- sh #%d, rowx=%d ---" % (self.number, rowx)) - elif rc in XL_FORMULA_OPCODES: # 06, 0206, 0406 - # DEBUG = 1 - # if DEBUG: print "FORMULA: rc: 0x%04x data: %r" % (rc, data) - if bv >= 50: - rowx, colx, xf_index, result_str, flags = local_unpack('= 30: - rowx, colx, xf_index, result_str, flags = local_unpack(' 255: break # Excel does 0 to 256 inclusive - self.colinfo_map[colx] = c - if 0: - fprintf(self.logfile, - "**COL %d %d %d\n", - self.number, colx, c.xf_index) - if blah: - fprintf( - self.logfile, - "COLINFO sheet #%d cols %d-%d: wid=%d xf_index=%d flags=0x%04x\n", - self.number, first_colx, last_colx, c.width, c.xf_index, flags, - ) - c.dump(self.logfile, header='===') - elif rc == XL_DEFCOLWIDTH: - self.defcolwidth, = local_unpack(">= 1 - self.gcw = tuple(gcw) - if 0: - showgcw = "".join(map(lambda x: "F "[x], gcw)).rstrip().replace(' ', '.') - print("GCW:", showgcw, file=self.logfile) - elif rc == XL_BLANK: - if not fmt_info: continue - rowx, colx, xf_index = local_unpack('> self.logfile, "BLANK", rowx, colx, xf_index - self_put_cell(rowx, colx, XL_CELL_BLANK, '', xf_index) - elif rc == XL_MULBLANK: # 00BE - if not fmt_info: continue - nitems = data_len >> 1 - result = local_unpack("<%dH" % nitems, data) - rowx, mul_first = result[:2] - mul_last = result[-1] - # print >> self.logfile, "MULBLANK", rowx, mul_first, mul_last, data_len, nitems, mul_last + 4 - mul_first - assert nitems == mul_last + 4 - mul_first - pos = 2 - for colx in xrange(mul_first, mul_last + 1): - self_put_cell(rowx, colx, XL_CELL_BLANK, '', result[pos]) - pos += 1 - elif rc == XL_DIMENSION or rc == XL_DIMENSION2: - if data_len == 0: - # Four zero bytes after some other record. See github issue 64. - continue - # if data_len == 10: - # Was crashing on BIFF 4.0 file w/o the two trailing unused bytes. - # Reported by Ralph Heimburger. - if bv < 80: - dim_tuple = local_unpack(' found EOF", file=self.logfile) - elif rc == XL_COUNTRY: - bk.handle_country(data) - elif rc == XL_LABELRANGES: - pos = 0 - pos = unpack_cell_range_address_list_update_pos( - self.row_label_ranges, data, pos, bv, addr_size=8, - ) - pos = unpack_cell_range_address_list_update_pos( - self.col_label_ranges, data, pos, bv, addr_size=8, - ) - assert pos == data_len - elif rc == XL_ARRAY: - row1x, rownx, col1x, colnx, array_flags, tokslen = \ - local_unpack("= 80 - num_CFs, needs_recalc, browx1, browx2, bcolx1, bcolx2 = \ - unpack("<6H", data[0:12]) - if self.verbosity >= 1: - fprintf(self.logfile, - "\n*** WARNING: Ignoring CONDFMT (conditional formatting) record\n" \ - "*** in Sheet %d (%r).\n" \ - "*** %d CF record(s); needs_recalc_or_redraw = %d\n" \ - "*** Bounding box is %s\n", - self.number, self.name, num_CFs, needs_recalc, - rangename2d(browx1, browx2+1, bcolx1, bcolx2+1), - ) - olist = [] # updated by the function - pos = unpack_cell_range_address_list_update_pos( - olist, data, 12, bv, addr_size=8) - # print >> self.logfile, repr(result), len(result) - if self.verbosity >= 1: - fprintf(self.logfile, - "*** %d individual range(s):\n" \ - "*** %s\n", - len(olist), - ", ".join([rangename2d(*coords) for coords in olist]), - ) - elif rc == XL_CF: - if not fmt_info: continue - cf_type, cmp_op, sz1, sz2, flags = unpack("> 26) & 1 - bord_block = (flags >> 28) & 1 - patt_block = (flags >> 29) & 1 - if self.verbosity >= 1: - fprintf(self.logfile, - "\n*** WARNING: Ignoring CF (conditional formatting) sub-record.\n" \ - "*** cf_type=%d, cmp_op=%d, sz1=%d, sz2=%d, flags=0x%08x\n" \ - "*** optional data blocks: font=%d, border=%d, pattern=%d\n", - cf_type, cmp_op, sz1, sz2, flags, - font_block, bord_block, patt_block, - ) - # hex_char_dump(data, 0, data_len, fout=self.logfile) - pos = 12 - if font_block: - (font_height, font_options, weight, escapement, underline, - font_colour_index, two_bits, font_esc, font_underl) = \ - unpack("<64x i i H H B 3x i 4x i i i 18x", data[pos:pos+118]) - font_style = (two_bits > 1) & 1 - posture = (font_options > 1) & 1 - font_canc = (two_bits > 7) & 1 - cancellation = (font_options > 7) & 1 - if self.verbosity >= 1: - fprintf(self.logfile, - "*** Font info: height=%d, weight=%d, escapement=%d,\n" \ - "*** underline=%d, colour_index=%d, esc=%d, underl=%d,\n" \ - "*** style=%d, posture=%d, canc=%d, cancellation=%d\n", - font_height, weight, escapement, underline, - font_colour_index, font_esc, font_underl, - font_style, posture, font_canc, cancellation, - ) - pos += 118 - if bord_block: - pos += 8 - if patt_block: - pos += 4 - fmla1 = data[pos:pos+sz1] - pos += sz1 - if blah and sz1: - fprintf(self.logfile, - "*** formula 1:\n", - ) - dump_formula(bk, fmla1, sz1, bv, reldelta=0, blah=1) - fmla2 = data[pos:pos+sz2] - pos += sz2 - assert pos == data_len - if blah and sz2: - fprintf(self.logfile, - "*** formula 2:\n", - ) - dump_formula(bk, fmla2, sz2, bv, reldelta=0, blah=1) - elif rc == XL_DEFAULTROWHEIGHT: - if data_len == 4: - bits, self.default_row_height = unpack("> 1) & 1 - self.default_additional_space_above = (bits >> 2) & 1 - self.default_additional_space_below = (bits >> 3) & 1 - elif rc == XL_MERGEDCELLS: - if not fmt_info: continue - pos = unpack_cell_range_address_list_update_pos( - self.merged_cells, data, 0, bv, addr_size=8) - if blah: - fprintf(self.logfile, - "MERGEDCELLS: %d ranges\n", (pos - 2) // 8) - assert pos == data_len, \ - "MERGEDCELLS: pos=%d data_len=%d" % (pos, data_len) - elif rc == XL_WINDOW2: - if bv >= 80 and data_len >= 14: - (options, - self.first_visible_rowx, self.first_visible_colx, - self.gridline_colour_index, - self.cached_page_break_preview_mag_factor, - self.cached_normal_view_mag_factor - ) = unpack("= 30 # BIFF3-7 - (options, - self.first_visible_rowx, self.first_visible_colx, - ) = unpack(">= 1 - elif rc == XL_SCL: - num, den = unpack("= 0: - print(( - "WARNING *** SCL rcd sheet %d: should have 0.1 <= num/den <= 4; got %d/%d" - % (self.number, num, den) - ), file=self.logfile) - result = 100 - self.scl_mag_factor = result - elif rc == XL_PANE: - ( - self.vert_split_pos, - self.horz_split_pos, - self.horz_split_first_visible, - self.vert_split_first_visible, - self.split_active_pane, - ) = unpack("= 80)) + 2 == data_len - pos = 2 - if bv < 80: - while pos < data_len: - self.horizontal_page_breaks.append((local_unpack("= 80)) + 2 == data_len - pos = 2 - if bv < 80: - while pos < data_len: - self.vertical_page_breaks.append((local_unpack("> 15) & 1 - r.has_default_xf_index = bits2 & 1 - r.xf_index = xf_index - # r.outline_level = 0 # set in __init__ - # r.outline_group_starts_ends = 0 # set in __init__ - # r.hidden = 0 # set in __init__ - # r.height_mismatch = 0 # set in __init__ - # r.additional_space_above = 0 # set in __init__ - # r.additional_space_below = 0 # set in __init__ - self.rowinfo_map[rowx] = r - if 0 and r.xf_index > -1: - fprintf(self.logfile, - "**ROW %d %d %d\n", - self.number, rowx, r.xf_index) - if blah_rows: - print('ROW_B2', rowx, bits1, has_defaults, file=self.logfile) - r.dump(self.logfile, - header="--- sh #%d, rowx=%d ---" % (self.number, rowx)) - elif rc == XL_COLWIDTH: # BIFF2 only - if not fmt_info: continue - first_colx, last_colx, width\ - = local_unpack("= 30) + 1 - nchars_expected = unpack("<" + "BH"[lenlen - 1], data[:lenlen])[0] - offset = lenlen - if bv < 80: - enc = bk.encoding or bk.derive_encoding() - nchars_found = 0 - result = UNICODE_LITERAL("") - while 1: - if bv >= 80: - flag = BYTES_ORD(data[offset]) & 1 - enc = ("latin_1", "utf_16_le")[flag] - offset += 1 - chunk = unicode(data[offset:], enc) - result += chunk - nchars_found += len(chunk) - if nchars_found == nchars_expected: - return result - if nchars_found > nchars_expected: - msg = ("STRING/CONTINUE: expected %d chars, found %d" - % (nchars_expected, nchars_found)) - raise XLRDError(msg) - rc, _unused_len, data = bk.get_record_parts() - if rc != XL_CONTINUE: - raise XLRDError( - "Expected CONTINUE record; found record-type 0x%04X" % rc) - offset = 0 - - def update_cooked_mag_factors(self): - # Cached values are used ONLY for the non-active view mode. - # When the user switches to the non-active view mode, - # if the cached value for that mode is not valid, - # Excel pops up a window which says: - # "The number must be between 10 and 400. Try again by entering a number in this range." - # When the user hits OK, it drops into the non-active view mode - # but uses the magn from the active mode. - # NOTE: definition of "valid" depends on mode ... see below - blah = DEBUG or self.verbosity > 0 - if self.show_in_page_break_preview: - if self.scl_mag_factor is None: # no SCL record - self.cooked_page_break_preview_mag_factor = 100 # Yes, 100, not 60, NOT a typo - else: - self.cooked_page_break_preview_mag_factor = self.scl_mag_factor - zoom = self.cached_normal_view_mag_factor - if not (10 <= zoom <=400): - if blah: - print(( - "WARNING *** WINDOW2 rcd sheet %d: Bad cached_normal_view_mag_factor: %d" - % (self.number, self.cached_normal_view_mag_factor) - ), file=self.logfile) - zoom = self.cooked_page_break_preview_mag_factor - self.cooked_normal_view_mag_factor = zoom - else: - # normal view mode - if self.scl_mag_factor is None: # no SCL record - self.cooked_normal_view_mag_factor = 100 - else: - self.cooked_normal_view_mag_factor = self.scl_mag_factor - zoom = self.cached_page_break_preview_mag_factor - if zoom == 0: - # VALID, defaults to 60 - zoom = 60 - elif not (10 <= zoom <= 400): - if blah: - print(( - "WARNING *** WINDOW2 rcd sheet %r: Bad cached_page_break_preview_mag_factor: %r" - % (self.number, self.cached_page_break_preview_mag_factor) - ), file=self.logfile) - zoom = self.cooked_normal_view_mag_factor - self.cooked_page_break_preview_mag_factor = zoom - - def fixed_BIFF2_xfindex(self, cell_attr, rowx, colx, true_xfx=None): - DEBUG = 0 - blah = DEBUG or self.verbosity >= 2 - if self.biff_version == 21: - if self.book.xf_list: - if true_xfx is not None: - xfx = true_xfx - else: - xfx = BYTES_ORD(cell_attr[0]) & 0x3F - if xfx == 0x3F: - if self._ixfe is None: - raise XLRDError("BIFF2 cell record has XF index 63 but no preceding IXFE record.") - xfx = self._ixfe - # OOo docs are capable of interpretation that each - # cell record is preceded immediately by its own IXFE record. - # Empirical evidence is that (sensibly) an IXFE record applies to all - # following cell records until another IXFE comes along. - return xfx - # Have either Excel 2.0, or broken 2.1 w/o XF records -- same effect. - self.biff_version = self.book.biff_version = 20 - #### check that XF slot in cell_attr is zero - xfx_slot = BYTES_ORD(cell_attr[0]) & 0x3F - assert xfx_slot == 0 - xfx = self._cell_attr_to_xfx.get(cell_attr) - if xfx is not None: - return xfx - if blah: - fprintf(self.logfile, "New cell_attr %r at (%r, %r)\n", cell_attr, rowx, colx) - if not self.book.xf_list: - for xfx in xrange(16): - self.insert_new_BIFF20_xf(cell_attr=b"\x40\x00\x00", style=xfx < 15) - xfx = self.insert_new_BIFF20_xf(cell_attr=cell_attr) - return xfx - - def insert_new_BIFF20_xf(self, cell_attr, style=0): - DEBUG = 0 - blah = DEBUG or self.verbosity >= 2 - book = self.book - xfx = len(book.xf_list) - xf = self.fake_XF_from_BIFF20_cell_attr(cell_attr, style) - xf.xf_index = xfx - book.xf_list.append(xf) - if blah: - xf.dump(self.logfile, header="=== Faked XF %d ===" % xfx, footer="======") - if xf.format_key not in book.format_map: - if xf.format_key: - msg = "ERROR *** XF[%d] unknown format key (%d, 0x%04x)\n" - fprintf(self.logfile, msg, - xf.xf_index, xf.format_key, xf.format_key) - fmt = Format(xf.format_key, FUN, UNICODE_LITERAL("General")) - book.format_map[xf.format_key] = fmt - book.format_list.append(fmt) - cellty_from_fmtty = { - FNU: XL_CELL_NUMBER, - FUN: XL_CELL_NUMBER, - FGE: XL_CELL_NUMBER, - FDT: XL_CELL_DATE, - FTX: XL_CELL_NUMBER, # Yes, a number can be formatted as text. - } - fmt = book.format_map[xf.format_key] - cellty = cellty_from_fmtty[fmt.type] - self._xf_index_to_xl_type_map[xf.xf_index] = cellty - self._cell_attr_to_xfx[cell_attr] = xfx - return xfx - - def fake_XF_from_BIFF20_cell_attr(self, cell_attr, style=0): - from .formatting import XF, XFAlignment, XFBorder, XFBackground, XFProtection - xf = XF() - xf.alignment = XFAlignment() - xf.alignment.indent_level = 0 - xf.alignment.shrink_to_fit = 0 - xf.alignment.text_direction = 0 - xf.border = XFBorder() - xf.border.diag_up = 0 - xf.border.diag_down = 0 - xf.border.diag_colour_index = 0 - xf.border.diag_line_style = 0 # no line - xf.background = XFBackground() - xf.protection = XFProtection() - (prot_bits, font_and_format, halign_etc) = unpack('> 6 - upkbits(xf.protection, prot_bits, ( - (6, 0x40, 'cell_locked'), - (7, 0x80, 'formula_hidden'), - )) - xf.alignment.hor_align = halign_etc & 0x07 - for mask, side in ((0x08, 'left'), (0x10, 'right'), (0x20, 'top'), (0x40, 'bottom')): - if halign_etc & mask: - colour_index, line_style = 8, 1 # black, thin - else: - colour_index, line_style = 0, 0 # none, none - setattr(xf.border, side + '_colour_index', colour_index) - setattr(xf.border, side + '_line_style', line_style) - bg = xf.background - if halign_etc & 0x80: - bg.fill_pattern = 17 - else: - bg.fill_pattern = 0 - bg.background_colour_index = 9 # white - bg.pattern_colour_index = 8 # black - xf.parent_style_index = (0x0FFF, 0)[style] - xf.alignment.vert_align = 2 # bottom - xf.alignment.rotation = 0 - for attr_stem in \ - "format font alignment border background protection".split(): - attr = "_" + attr_stem + "_flag" - setattr(xf, attr, 1) - return xf - - def req_fmt_info(self): - if not self.formatting_info: - raise XLRDError("Feature requires open_workbook(..., formatting_info=True)") - - ## - # Determine column display width. - #
    -- New in version 0.6.1 - #
    - # @param colx Index of the queried column, range 0 to 255. - # Note that it is possible to find out the width that will be used to display - # columns with no cell information e.g. column IV (colx=255). - # @return The column width that will be used for displaying - # the given column by Excel, in units of 1/256th of the width of a - # standard character (the digit zero in the first font). - - def computed_column_width(self, colx): - self.req_fmt_info() - if self.biff_version >= 80: - colinfo = self.colinfo_map.get(colx, None) - if colinfo is not None: - return colinfo.width - if self.standardwidth is not None: - return self.standardwidth - elif self.biff_version >= 40: - if self.gcw[colx]: - if self.standardwidth is not None: - return self.standardwidth - else: - colinfo = self.colinfo_map.get(colx, None) - if colinfo is not None: - return colinfo.width - elif self.biff_version == 30: - colinfo = self.colinfo_map.get(colx, None) - if colinfo is not None: - return colinfo.width - # All roads lead to Rome and the DEFCOLWIDTH ... - if self.defcolwidth is not None: - return self.defcolwidth * 256 - return 8 * 256 # 8 is what Excel puts in a DEFCOLWIDTH record - - def handle_hlink(self, data): - # DEBUG = 1 - if DEBUG: print("\n=== hyperlink ===", file=self.logfile) - record_size = len(data) - h = Hyperlink() - h.frowx, h.lrowx, h.fcolx, h.lcolx, guid0, dummy, options = unpack(' 0: - fprintf( - self.logfile, - "*** WARNING: hyperlink at r=%d c=%d has %d extra data bytes: %s\n", - h.frowx, - h.fcolx, - extra_nbytes, - REPR(data[-extra_nbytes:]) - ) - # Seen: b"\x00\x00" also b"A\x00", b"V\x00" - elif extra_nbytes < 0: - raise XLRDError("Bug or corrupt file, send copy of input file for debugging") - - self.hyperlink_list.append(h) - for rowx in xrange(h.frowx, h.lrowx+1): - for colx in xrange(h.fcolx, h.lcolx+1): - self.hyperlink_map[rowx, colx] = h - - def handle_quicktip(self, data): - rcx, frowx, lrowx, fcolx, lcolx = unpack('<5H', data[:10]) - assert rcx == XL_QUICKTIP - assert self.hyperlink_list - h = self.hyperlink_list[-1] - assert (frowx, lrowx, fcolx, lcolx) == (h.frowx, h.lrowx, h.fcolx, h.lcolx) - assert data[-2:] == b'\x00\x00' - h.quicktip = unicode(data[10:-2], 'utf_16_le') - - def handle_msodrawingetc(self, recid, data_len, data): - if not OBJ_MSO_DEBUG: - return - DEBUG = 1 - if self.biff_version < 80: - return - o = MSODrawing() - pos = 0 - while pos < data_len: - tmp, fbt, cb = unpack('> 4) & 0xFFF - if ver == 0xF: - ndb = 0 # container - else: - ndb = cb - if DEBUG: - hex_char_dump(data, pos, ndb + 8, base=0, fout=self.logfile) - fprintf(self.logfile, - "fbt:0x%04X inst:%d ver:0x%X cb:%d (0x%04X)\n", - fbt, inst, ver, cb, cb) - if fbt == 0xF010: # Client Anchor - assert ndb == 18 - (o.anchor_unk, - o.anchor_colx_lo, o.anchor_rowx_lo, - o.anchor_colx_hi, o.anchor_rowx_hi) = unpack(' 0: - rc2, data2_len, data2 = self.book.get_record_parts() - assert rc2 == XL_NOTE - dummy_rowx, nb = unpack('> 1) & 1 - o.row_hidden = (option_flags >> 7) & 1 - o.col_hidden = (option_flags >> 8) & 1 - # XL97 dev kit book says NULL [sic] bytes padding between string count and string data - # to ensure that string is word-aligned. Appears to be nonsense. - o.author, endpos = unpack_unicode_update_pos(data, 8, lenlen=2) - # There is a random/undefined byte after the author string (not counted in the - # string length). - # Issue 4 on github: Google Spreadsheet doesn't write the undefined byte. - assert (data_len - endpos) in (0, 1) - if OBJ_MSO_DEBUG: - o.dump(self.logfile, header="=== Note ===", footer= " ") - txo = txos.get(o._object_id) - if txo: - o.text = txo.text - o.rich_text_runlist = txo.rich_text_runlist - self.cell_note_map[o.rowx, o.colx] = o - - def handle_txo(self, data): - if self.biff_version < 80: - return - o = MSTxo() - data_len = len(data) - fmt = ' Represents a user "comment" or "note". -# Note objects are accessible through Sheet.{@link #Sheet.cell_note_map}. -#
    -- New in version 0.7.2 -#

    -class Note(BaseObject): - ## - # Author of note - author = UNICODE_LITERAL('') - ## - # True if the containing column is hidden - col_hidden = 0 - ## - # Column index - colx = 0 - ## - # List of (offset_in_string, font_index) tuples. - # Unlike Sheet.{@link #Sheet.rich_text_runlist_map}, the first offset should always be 0. - rich_text_runlist = None - ## - # True if the containing row is hidden - row_hidden = 0 - ## - # Row index - rowx = 0 - ## - # True if note is always shown - show = 0 - ## - # Text of the note - text = UNICODE_LITERAL('') - -## -#

    Contains the attributes of a hyperlink. -# Hyperlink objects are accessible through Sheet.{@link #Sheet.hyperlink_list} -# and Sheet.{@link #Sheet.hyperlink_map}. -#
    -- New in version 0.7.2 -#

    -class Hyperlink(BaseObject): - ## - # Index of first row - frowx = None - ## - # Index of last row - lrowx = None - ## - # Index of first column - fcolx = None - ## - # Index of last column - lcolx = None - ## - # Type of hyperlink. Unicode string, one of 'url', 'unc', - # 'local file', 'workbook', 'unknown' - type = None - ## - # The URL or file-path, depending in the type. Unicode string, except - # in the rare case of a local but non-existent file with non-ASCII - # characters in the name, in which case only the "8.3" filename is available, - # as a bytes (3.x) or str (2.x) string, with unknown encoding. - url_or_path = None - ## - # Description ... this is displayed in the cell, - # and should be identical to the cell value. Unicode string, or None. It seems - # impossible NOT to have a description created by the Excel UI. - desc = None - ## - # Target frame. Unicode string. Note: I have not seen a case of this. - # It seems impossible to create one in the Excel UI. - target = None - ## - # "Textmark": the piece after the "#" in - # "http://docs.python.org/library#struct_module", or the Sheet1!A1:Z99 - # part when type is "workbook". - textmark = None - ## - # The text of the "quick tip" displayed when the cursor - # hovers over the hyperlink. - quicktip = None - -# === helpers === - -def unpack_RK(rk_str): - flags = BYTES_ORD(rk_str[0]) - if flags & 2: - # There's a SIGNED 30-bit integer in there! - i, = unpack('>= 2 # div by 4 to drop the 2 flag bits - if flags & 1: - return i / 100.0 - return float(i) - else: - # It's the most significant 30 bits of an IEEE 754 64-bit FP number - d, = unpack('Contains the data for one cell.

    -# -#

    WARNING: You don't call this class yourself. You access Cell objects -# via methods of the {@link #Sheet} object(s) that you found in the {@link #Book} object that -# was returned when you called xlrd.open_workbook("myfile.xls").

    -#

    Cell objects have three attributes: ctype is an int, value -# (which depends on ctype) and xf_index. -# If "formatting_info" is not enabled when the workbook is opened, xf_index will be None. -# The following table describes the types of cells and how their values -# are represented in Python.

    -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -#
    Type symbolType numberPython value
    XL_CELL_EMPTY0empty string u''
    XL_CELL_TEXT1a Unicode string
    XL_CELL_NUMBER2float
    XL_CELL_DATE3float
    XL_CELL_BOOLEAN4int; 1 means TRUE, 0 means FALSE
    XL_CELL_ERROR5int representing internal Excel codes; for a text representation, -# refer to the supplied dictionary error_text_from_code
    XL_CELL_BLANK6empty string u''. Note: this type will appear only when -# open_workbook(..., formatting_info=True) is used.
    -#

    - -class Cell(BaseObject): - - __slots__ = ['ctype', 'value', 'xf_index'] - - def __init__(self, ctype, value, xf_index=None): - self.ctype = ctype - self.value = value - self.xf_index = xf_index - - def __repr__(self): - if self.xf_index is None: - return "%s:%r" % (ctype_text[self.ctype], self.value) - else: - return "%s:%r (XF:%r)" % (ctype_text[self.ctype], self.value, self.xf_index) - -## -# There is one and only one instance of an empty cell -- it's a singleton. This is it. -# You may use a test like "acell is empty_cell". -empty_cell = Cell(XL_CELL_EMPTY, '') - -##### =============== Colinfo and Rowinfo ============================== ##### - -## -# Width and default formatting information that applies to one or -# more columns in a sheet. Derived from COLINFO records. -# -#

    Here is the default hierarchy for width, according to the OOo docs: -# -#
    """In BIFF3, if a COLINFO record is missing for a column, -# the width specified in the record DEFCOLWIDTH is used instead. -# -#
    In BIFF4-BIFF7, the width set in this [COLINFO] record is only used, -# if the corresponding bit for this column is cleared in the GCW -# record, otherwise the column width set in the DEFCOLWIDTH record -# is used (the STANDARDWIDTH record is always ignored in this case [see footnote!]). -# -#
    In BIFF8, if a COLINFO record is missing for a column, -# the width specified in the record STANDARDWIDTH is used. -# If this [STANDARDWIDTH] record is also missing, -# the column width of the record DEFCOLWIDTH is used instead.""" -#
    -# -# Footnote: The docs on the GCW record say this: -# """
    -# If a bit is set, the corresponding column uses the width set in the STANDARDWIDTH -# record. If a bit is cleared, the corresponding column uses the width set in the -# COLINFO record for this column. -#
    If a bit is set, and the worksheet does not contain the STANDARDWIDTH record, or if -# the bit is cleared, and the worksheet does not contain the COLINFO record, the DEFCOLWIDTH -# record of the worksheet will be used instead. -#
    """
    -# At the moment (2007-01-17) xlrd is going with the GCW version of the story. -# Reference to the source may be useful: see the computed_column_width(colx) method -# of the Sheet class. -#
    -- New in version 0.6.1 -#

    - -class Colinfo(BaseObject): - ## - # Width of the column in 1/256 of the width of the zero character, - # using default font (first FONT record in the file). - width = 0 - ## - # XF index to be used for formatting empty cells. - xf_index = -1 - ## - # 1 = column is hidden - hidden = 0 - ## - # Value of a 1-bit flag whose purpose is unknown - # but is often seen set to 1 - bit1_flag = 0 - ## - # Outline level of the column, in range(7). - # (0 = no outline) - outline_level = 0 - ## - # 1 = column is collapsed - collapsed = 0 - -_USE_SLOTS = 1 - -## -#

    Height and default formatting information that applies to a row in a sheet. -# Derived from ROW records. -#
    -- New in version 0.6.1

    -# -#

    height: Height of the row, in twips. One twip == 1/20 of a point.

    -# -#

    has_default_height: 0 = Row has custom height; 1 = Row has default height.

    -# -#

    outline_level: Outline level of the row (0 to 7)

    -# -#

    outline_group_starts_ends: 1 = Outline group starts or ends here (depending on where the -# outline buttons are located, see WSBOOL record [TODO ??]), -# and is collapsed

    -# -#

    hidden: 1 = Row is hidden (manually, or by a filter or outline group)

    -# -#

    height_mismatch: 1 = Row height and default font height do not match

    -# -#

    has_default_xf_index: 1 = the xf_index attribute is usable; 0 = ignore it

    -# -#

    xf_index: Index to default XF record for empty cells in this row. -# Don't use this if has_default_xf_index == 0.

    -# -#

    additional_space_above: This flag is set, if the upper border of at least one cell in this row -# or if the lower border of at least one cell in the row above is -# formatted with a thick line style. Thin and medium line styles are not -# taken into account.

    -# -#

    additional_space_below: This flag is set, if the lower border of at least one cell in this row -# or if the upper border of at least one cell in the row below is -# formatted with a medium or thick line style. Thin line styles are not -# taken into account.

    - -class Rowinfo(BaseObject): - - if _USE_SLOTS: - __slots__ = ( - "height", - "has_default_height", - "outline_level", - "outline_group_starts_ends", - "hidden", - "height_mismatch", - "has_default_xf_index", - "xf_index", - "additional_space_above", - "additional_space_below", - ) - - def __init__(self): - self.height = None - self.has_default_height = None - self.outline_level = None - self.outline_group_starts_ends = None - self.hidden = None - self.height_mismatch = None - self.has_default_xf_index = None - self.xf_index = None - self.additional_space_above = None - self.additional_space_below = None - - def __getstate__(self): - return ( - self.height, - self.has_default_height, - self.outline_level, - self.outline_group_starts_ends, - self.hidden, - self.height_mismatch, - self.has_default_xf_index, - self.xf_index, - self.additional_space_above, - self.additional_space_below, - ) - - def __setstate__(self, state): - ( - self.height, - self.has_default_height, - self.outline_level, - self.outline_group_starts_ends, - self.hidden, - self.height_mismatch, - self.has_default_xf_index, - self.xf_index, - self.additional_space_above, - self.additional_space_below, - ) = state diff --git a/webhub/xlrd/sheet.pyc b/webhub/xlrd/sheet.pyc deleted file mode 100644 index 6432c52b..00000000 Binary files a/webhub/xlrd/sheet.pyc and /dev/null differ diff --git a/webhub/xlrd/timemachine.py b/webhub/xlrd/timemachine.py deleted file mode 100644 index a068db3e..00000000 --- a/webhub/xlrd/timemachine.py +++ /dev/null @@ -1,52 +0,0 @@ -## -#

    Copyright (c) 2006-2012 Stephen John Machin, Lingfo Pty Ltd

    -#

    This module is part of the xlrd package, which is released under a BSD-style licence.

    -## - -# timemachine.py -- adaptation for single codebase. -# Currently supported: 2.6 to 2.7, 3.2+ -# usage: from timemachine import * - -from __future__ import print_function -import sys - -python_version = sys.version_info[:2] # e.g. version 2.6 -> (2, 6) - -if python_version >= (3, 0): - # Python 3 - BYTES_LITERAL = lambda x: x.encode('latin1') - UNICODE_LITERAL = lambda x: x - BYTES_ORD = lambda byte: byte - from io import BytesIO as BYTES_IO - def fprintf(f, fmt, *vargs): - fmt = fmt.replace("%r", "%a") - if fmt.endswith('\n'): - print(fmt[:-1] % vargs, file=f) - else: - print(fmt % vargs, end=' ', file=f) - EXCEL_TEXT_TYPES = (str, bytes, bytearray) # xlwt: isinstance(obj, EXCEL_TEXT_TYPES) - REPR = ascii - xrange = range - unicode = lambda b, enc: b.decode(enc) - ensure_unicode = lambda s: s - unichr = chr -else: - # Python 2 - BYTES_LITERAL = lambda x: x - UNICODE_LITERAL = lambda x: x.decode('latin1') - BYTES_ORD = ord - from cStringIO import StringIO as BYTES_IO - def fprintf(f, fmt, *vargs): - if fmt.endswith('\n'): - print(fmt[:-1] % vargs, file=f) - else: - print(fmt % vargs, end=' ', file=f) - try: - EXCEL_TEXT_TYPES = basestring # xlwt: isinstance(obj, EXCEL_TEXT_TYPES) - except NameError: - EXCEL_TEXT_TYPES = (str, unicode) - REPR = repr - xrange = xrange - # following used only to overcome 2.x ElementTree gimmick which - # returns text as `str` if it's ascii, otherwise `unicode` - ensure_unicode = unicode # used only in xlsx.py diff --git a/webhub/xlrd/timemachine.pyc b/webhub/xlrd/timemachine.pyc deleted file mode 100644 index 7c8a9952..00000000 Binary files a/webhub/xlrd/timemachine.pyc and /dev/null differ diff --git a/webhub/xlrd/xldate.py b/webhub/xlrd/xldate.py deleted file mode 100644 index dc7b9c87..00000000 --- a/webhub/xlrd/xldate.py +++ /dev/null @@ -1,213 +0,0 @@ -# -*- coding: cp1252 -*- - -# No part of the content of this file was derived from the works of David Giffin. - -## -#

    Copyright 2005-2008 Stephen John Machin, Lingfo Pty Ltd

    -#

    This module is part of the xlrd package, which is released under a BSD-style licence.

    -# -#

    Provides function(s) for dealing with Microsoft Excel dates.

    -## - -# 2008-10-18 SJM Fix bug in xldate_from_date_tuple (affected some years after 2099) - -# The conversion from days to (year, month, day) starts with -# an integral "julian day number" aka JDN. -# FWIW, JDN 0 corresponds to noon on Monday November 24 in Gregorian year -4713. -# More importantly: -# Noon on Gregorian 1900-03-01 (day 61 in the 1900-based system) is JDN 2415080.0 -# Noon on Gregorian 1904-01-02 (day 1 in the 1904-based system) is JDN 2416482.0 -import datetime - -_JDN_delta = (2415080 - 61, 2416482 - 1) -assert _JDN_delta[1] - _JDN_delta[0] == 1462 - -# Pre-calculate the datetime epochs for efficiency. -epoch_1904 = datetime.datetime(1904, 1, 1) -epoch_1900 = datetime.datetime(1899, 12, 31) -epoch_1900_minus_1 = datetime.datetime(1899, 12, 30) - -class XLDateError(ValueError): pass - -class XLDateNegative(XLDateError): pass -class XLDateAmbiguous(XLDateError): pass -class XLDateTooLarge(XLDateError): pass -class XLDateBadDatemode(XLDateError): pass -class XLDateBadTuple(XLDateError): pass - -_XLDAYS_TOO_LARGE = (2958466, 2958466 - 1462) # This is equivalent to 10000-01-01 - -## -# Convert an Excel number (presumed to represent a date, a datetime or a time) into -# a tuple suitable for feeding to datetime or mx.DateTime constructors. -# @param xldate The Excel number -# @param datemode 0: 1900-based, 1: 1904-based. -#
    WARNING: when using this function to -# interpret the contents of a workbook, you should pass in the Book.datemode -# attribute of that workbook. Whether -# the workbook has ever been anywhere near a Macintosh is irrelevant. -# @return Gregorian (year, month, day, hour, minute, nearest_second). -#
    Special case: if 0.0 <= xldate < 1.0, it is assumed to represent a time; -# (0, 0, 0, hour, minute, second) will be returned. -#
    Note: 1904-01-01 is not regarded as a valid date in the datemode 1 system; its "serial number" -# is zero. -# @throws XLDateNegative xldate < 0.00 -# @throws XLDateAmbiguous The 1900 leap-year problem (datemode == 0 and 1.0 <= xldate < 61.0) -# @throws XLDateTooLarge Gregorian year 10000 or later -# @throws XLDateBadDatemode datemode arg is neither 0 nor 1 -# @throws XLDateError Covers the 4 specific errors - -def xldate_as_tuple(xldate, datemode): - if datemode not in (0, 1): - raise XLDateBadDatemode(datemode) - if xldate == 0.00: - return (0, 0, 0, 0, 0, 0) - if xldate < 0.00: - raise XLDateNegative(xldate) - xldays = int(xldate) - frac = xldate - xldays - seconds = int(round(frac * 86400.0)) - assert 0 <= seconds <= 86400 - if seconds == 86400: - hour = minute = second = 0 - xldays += 1 - else: - # second = seconds % 60; minutes = seconds // 60 - minutes, second = divmod(seconds, 60) - # minute = minutes % 60; hour = minutes // 60 - hour, minute = divmod(minutes, 60) - if xldays >= _XLDAYS_TOO_LARGE[datemode]: - raise XLDateTooLarge(xldate) - - if xldays == 0: - return (0, 0, 0, hour, minute, second) - - if xldays < 61 and datemode == 0: - raise XLDateAmbiguous(xldate) - - jdn = xldays + _JDN_delta[datemode] - yreg = ((((jdn * 4 + 274277) // 146097) * 3 // 4) + jdn + 1363) * 4 + 3 - mp = ((yreg % 1461) // 4) * 535 + 333 - d = ((mp % 16384) // 535) + 1 - # mp /= 16384 - mp >>= 14 - if mp >= 10: - return ((yreg // 1461) - 4715, mp - 9, d, hour, minute, second) - else: - return ((yreg // 1461) - 4716, mp + 3, d, hour, minute, second) - - -## -# Convert an Excel date/time number into a datetime.datetime object. -# -# @param xldate The Excel number -# @param datemode 0: 1900-based, 1: 1904-based. -# -# @return a datetime.datetime() object. -# -def xldate_as_datetime(xldate, datemode): - """Convert an Excel date/time number into a datetime.datetime object.""" - - # Set the epoch based on the 1900/1904 datemode. - if datemode: - epoch = epoch_1904 - else: - if xldate < 60: - epoch = epoch_1900 - else: - # Workaround Excel 1900 leap year bug by adjusting the epoch. - epoch = epoch_1900_minus_1 - - # The integer part of the Excel date stores the number of days since - # the epoch and the fractional part stores the percentage of the day. - days = int(xldate) - fraction = xldate - days - - # Get the the integer and decimal seconds in Excel's millisecond resolution. - seconds = int(round(fraction * 86400000.0)) - seconds, milliseconds = divmod(seconds, 1000) - - return epoch + datetime.timedelta(days, seconds, 0, milliseconds) - - -# === conversions from date/time to xl numbers - -def _leap(y): - if y % 4: return 0 - if y % 100: return 1 - if y % 400: return 0 - return 1 - -_days_in_month = (None, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) - -## -# Convert a date tuple (year, month, day) to an Excel date. -# @param year Gregorian year. -# @param month 1 <= month <= 12 -# @param day 1 <= day <= last day of that (year, month) -# @param datemode 0: 1900-based, 1: 1904-based. -# @throws XLDateAmbiguous The 1900 leap-year problem (datemode == 0 and 1.0 <= xldate < 61.0) -# @throws XLDateBadDatemode datemode arg is neither 0 nor 1 -# @throws XLDateBadTuple (year, month, day) is too early/late or has invalid component(s) -# @throws XLDateError Covers the specific errors - -def xldate_from_date_tuple(date_tuple, datemode): - """Create an excel date from a tuple of (year, month, day)""" - year, month, day = date_tuple - - if datemode not in (0, 1): - raise XLDateBadDatemode(datemode) - - if year == 0 and month == 0 and day == 0: - return 0.00 - - if not (1900 <= year <= 9999): - raise XLDateBadTuple("Invalid year: %r" % ((year, month, day),)) - if not (1 <= month <= 12): - raise XLDateBadTuple("Invalid month: %r" % ((year, month, day),)) - if day < 1 \ - or (day > _days_in_month[month] and not(day == 29 and month == 2 and _leap(year))): - raise XLDateBadTuple("Invalid day: %r" % ((year, month, day),)) - - Yp = year + 4716 - M = month - if M <= 2: - Yp = Yp - 1 - Mp = M + 9 - else: - Mp = M - 3 - jdn = (1461 * Yp // 4) + ((979 * Mp + 16) // 32) + \ - day - 1364 - (((Yp + 184) // 100) * 3 // 4) - xldays = jdn - _JDN_delta[datemode] - if xldays <= 0: - raise XLDateBadTuple("Invalid (year, month, day): %r" % ((year, month, day),)) - if xldays < 61 and datemode == 0: - raise XLDateAmbiguous("Before 1900-03-01: %r" % ((year, month, day),)) - return float(xldays) - -## -# Convert a time tuple (hour, minute, second) to an Excel "date" value (fraction of a day). -# @param hour 0 <= hour < 24 -# @param minute 0 <= minute < 60 -# @param second 0 <= second < 60 -# @throws XLDateBadTuple Out-of-range hour, minute, or second - -def xldate_from_time_tuple(time_tuple): - """Create an excel date from a tuple of (hour, minute, second)""" - hour, minute, second = time_tuple - if 0 <= hour < 24 and 0 <= minute < 60 and 0 <= second < 60: - return ((second / 60.0 + minute) / 60.0 + hour) / 24.0 - raise XLDateBadTuple("Invalid (hour, minute, second): %r" % ((hour, minute, second),)) - -## -# Convert a datetime tuple (year, month, day, hour, minute, second) to an Excel date value. -# For more details, refer to other xldate_from_*_tuple functions. -# @param datetime_tuple (year, month, day, hour, minute, second) -# @param datemode 0: 1900-based, 1: 1904-based. - -def xldate_from_datetime_tuple(datetime_tuple, datemode): - return ( - xldate_from_date_tuple(datetime_tuple[:3], datemode) - + - xldate_from_time_tuple(datetime_tuple[3:]) - ) diff --git a/webhub/xlrd/xldate.pyc b/webhub/xlrd/xldate.pyc deleted file mode 100644 index ef7b265b..00000000 Binary files a/webhub/xlrd/xldate.pyc and /dev/null differ diff --git a/webhub/xlrd/xlsx.py b/webhub/xlrd/xlsx.py deleted file mode 100644 index 53fbb892..00000000 --- a/webhub/xlrd/xlsx.py +++ /dev/null @@ -1,801 +0,0 @@ -## -# Portions copyright (c) 2008-2012 Stephen John Machin, Lingfo Pty Ltd -# This module is part of the xlrd package, which is released under a BSD-style licence. -## - -from __future__ import print_function, unicode_literals - -DEBUG = 0 - -import sys -import re -from .timemachine import * -from .book import Book, Name -from .biffh import error_text_from_code, XLRDError, XL_CELL_BLANK, XL_CELL_TEXT, XL_CELL_BOOLEAN, XL_CELL_ERROR -from .formatting import is_date_format_string, Format, XF -from .sheet import Sheet - -DLF = sys.stdout # Default Log File - -ET = None -ET_has_iterparse = False - -def ensure_elementtree_imported(verbosity, logfile): - global ET, ET_has_iterparse - if ET is not None: - return - if "IronPython" in sys.version: - import xml.etree.ElementTree as ET - #### 2.7.2.1: fails later with - #### NotImplementedError: iterparse is not supported on IronPython. (CP #31923) - else: - try: import xml.etree.cElementTree as ET - except ImportError: - try: import cElementTree as ET - except ImportError: - try: import lxml.etree as ET - except ImportError: - try: import xml.etree.ElementTree as ET - except ImportError: - try: import elementtree.ElementTree as ET - except ImportError: - raise Exception("Failed to import an ElementTree implementation") - if hasattr(ET, 'iterparse'): - _dummy_stream = BYTES_IO(b'') - try: - ET.iterparse(_dummy_stream) - ET_has_iterparse = True - except NotImplementedError: - pass - if verbosity: - etree_version = repr([ - (item, getattr(ET, item)) - for item in ET.__dict__.keys() - if item.lower().replace('_', '') == 'version' - ]) - print(ET.__file__, ET.__name__, etree_version, ET_has_iterparse, file=logfile) - -def split_tag(tag): - pos = tag.rfind('}') + 1 - if pos >= 2: - return tag[:pos], tag[pos:] - return '', tag - -def augment_keys(adict, uri): - # uri must already be enclosed in {} - for x in list(adict.keys()): - adict[uri + x] = adict[x] - -_UPPERCASE_1_REL_INDEX = {} # Used in fast conversion of column names (e.g. "XFD") to indices (16383) -for _x in xrange(26): - _UPPERCASE_1_REL_INDEX["ABCDEFGHIJKLMNOPQRSTUVWXYZ"[_x]] = _x + 1 -for _x in "123456789": - _UPPERCASE_1_REL_INDEX[_x] = 0 -del _x - -def cell_name_to_rowx_colx(cell_name, letter_value=_UPPERCASE_1_REL_INDEX): - # Extract column index from cell name - # A => 0, Z =>25, AA => 26, XFD => 16383 - colx = 0 - charx = -1 - try: - for c in cell_name: - charx += 1 - lv = letter_value[c] - if lv: - colx = colx * 26 + lv - else: # start of row number; can't be '0' - colx = colx - 1 - assert 0 <= colx < X12_MAX_COLS - break - except KeyError: - raise Exception('Unexpected character %r in cell name %r' % (c, cell_name)) - rowx = int(cell_name[charx:]) - 1 - return rowx, colx - -error_code_from_text = {} -for _code, _text in error_text_from_code.items(): - error_code_from_text[_text] = _code - -# === X12 === Excel 2007 .xlsx =============================================== - -U_SSML12 = "{http://schemas.openxmlformats.org/spreadsheetml/2006/main}" -U_ODREL = "{http://schemas.openxmlformats.org/officeDocument/2006/relationships}" -U_PKGREL = "{http://schemas.openxmlformats.org/package/2006/relationships}" -U_CP = "{http://schemas.openxmlformats.org/package/2006/metadata/core-properties}" -U_DC = "{http://purl.org/dc/elements/1.1/}" -U_DCTERMS = "{http://purl.org/dc/terms/}" -XML_SPACE_ATTR = "{http://www.w3.org/XML/1998/namespace}space" -XML_WHITESPACE = "\t\n \r" -X12_MAX_ROWS = 2 ** 20 -X12_MAX_COLS = 2 ** 14 -V_TAG = U_SSML12 + 'v' # cell child: value -F_TAG = U_SSML12 + 'f' # cell child: formula -IS_TAG = U_SSML12 + 'is' # cell child: inline string - -def unescape(s, - subber=re.compile(r'_x[0-9A-Fa-f]{4,4}_', re.UNICODE).sub, - repl=lambda mobj: unichr(int(mobj.group(0)[2:6], 16)), - ): - if "_" in s: - return subber(repl, s) - return s - -def cooked_text(self, elem): - t = elem.text - if t is None: - return '' - if elem.get(XML_SPACE_ATTR) != 'preserve': - t = t.strip(XML_WHITESPACE) - return ensure_unicode(unescape(t)) - -def get_text_from_si_or_is(self, elem, r_tag=U_SSML12+'r', t_tag=U_SSML12 +'t'): - "Returns unescaped unicode" - accum = [] - for child in elem: - # self.dump_elem(child) - tag = child.tag - if tag == t_tag: - t = cooked_text(self, child) - if t: # note: .text attribute can be None - accum.append(t) - elif tag == r_tag: - for tnode in child: - if tnode.tag == t_tag: - t = cooked_text(self, tnode) - if t: - accum.append(t) - return ''.join(accum) - -def map_attributes(amap, elem, obj): - for xml_attr, obj_attr, cnv_func_or_const in amap: - if not xml_attr: - setattr(obj, obj_attr, cnv_func_or_const) - continue - if not obj_attr: continue #### FIX ME #### - raw_value = elem.get(xml_attr) - cooked_value = cnv_func_or_const(raw_value) - setattr(obj, obj_attr, cooked_value) - -def cnv_ST_Xstring(s): - if s is None: return "" - return ensure_unicode(s) - -def cnv_xsd_unsignedInt(s): - if not s: - return None - value = int(s) - assert value >= 0 - return value - -def cnv_xsd_boolean(s): - if not s: - return 0 - if s in ("1", "true", "on"): - return 1 - if s in ("0", "false", "off"): - return 0 - raise ValueError("unexpected xsd:boolean value: %r" % s) - - -_defined_name_attribute_map = ( - ("name", "name", cnv_ST_Xstring, ), - ("comment", "", cnv_ST_Xstring, ), - ("customMenu", "", cnv_ST_Xstring, ), - ("description", "", cnv_ST_Xstring, ), - ("help", "", cnv_ST_Xstring, ), - ("statusBar", "", cnv_ST_Xstring, ), - ("localSheetId", "scope", cnv_xsd_unsignedInt, ), - ("hidden", "hidden", cnv_xsd_boolean, ), - ("function", "func", cnv_xsd_boolean, ), - ("vbProcedure", "vbasic", cnv_xsd_boolean, ), - ("xlm", "macro", cnv_xsd_boolean, ), - ("functionGroupId", "funcgroup", cnv_xsd_unsignedInt, ), - ("shortcutKey", "", cnv_ST_Xstring, ), - ("publishToServer", "", cnv_xsd_boolean, ), - ("workbookParameter", "", cnv_xsd_boolean, ), - ("", "any_err", 0, ), - ("", "any_external", 0, ), - ("", "any_rel", 0, ), - ("", "basic_formula_len", 0, ), - ("", "binary", 0, ), - ("", "builtin", 0, ), - ("", "complex", 0, ), - ("", "evaluated", 0, ), - ("", "excel_sheet_index", 0, ), - ("", "excel_sheet_num", 0, ), - ("", "option_flags", 0, ), - ("", "result", None, ), - ("", "stack", None, ), - ) - -def make_name_access_maps(bk): - name_and_scope_map = {} # (name.lower(), scope): Name_object - name_map = {} # name.lower() : list of Name_objects (sorted in scope order) - num_names = len(bk.name_obj_list) - for namex in xrange(num_names): - nobj = bk.name_obj_list[namex] - name_lcase = nobj.name.lower() - key = (name_lcase, nobj.scope) - if key in name_and_scope_map: - msg = 'Duplicate entry %r in name_and_scope_map' % (key, ) - if 0: - raise XLRDError(msg) - else: - if bk.verbosity: - print(msg, file=bk.logfile) - name_and_scope_map[key] = nobj - if name_lcase in name_map: - name_map[name_lcase].append((nobj.scope, nobj)) - else: - name_map[name_lcase] = [(nobj.scope, nobj)] - for key in name_map.keys(): - alist = name_map[key] - alist.sort() - name_map[key] = [x[1] for x in alist] - bk.name_and_scope_map = name_and_scope_map - bk.name_map = name_map - -class X12General(object): - - def process_stream(self, stream, heading=None): - if self.verbosity >= 2 and heading is not None: - fprintf(self.logfile, "\n=== %s ===\n", heading) - self.tree = ET.parse(stream) - getmethod = self.tag2meth.get - for elem in self.tree.getiterator(): - if self.verbosity >= 3: - self.dump_elem(elem) - meth = getmethod(elem.tag) - if meth: - meth(self, elem) - self.finish_off() - - def finish_off(self): - pass - - def dump_elem(self, elem): - fprintf(self.logfile, - "===\ntag=%r len=%d attrib=%r text=%r tail=%r\n", - split_tag(elem.tag)[1], len(elem), elem.attrib, elem.text, elem.tail) - - def dumpout(self, fmt, *vargs): - text = (12 * ' ' + fmt + '\n') % vargs - self.logfile.write(text) - -class X12Book(X12General): - - def __init__(self, bk, logfile=DLF, verbosity=False): - self.bk = bk - self.logfile = logfile - self.verbosity = verbosity - self.bk.nsheets = 0 - self.bk.props = {} - self.relid2path = {} - self.relid2reltype = {} - self.sheet_targets = [] # indexed by sheetx - self.sheetIds = [] # indexed by sheetx - - core_props_menu = { - U_CP+"lastModifiedBy": ("last_modified_by", cnv_ST_Xstring), - U_DC+"creator": ("creator", cnv_ST_Xstring), - U_DCTERMS+"modified": ("modified", cnv_ST_Xstring), - U_DCTERMS+"created": ("created", cnv_ST_Xstring), - } - - def process_coreprops(self, stream): - if self.verbosity >= 2: - fprintf(self.logfile, "\n=== coreProps ===\n") - self.tree = ET.parse(stream) - getmenu = self.core_props_menu.get - props = {} - for elem in self.tree.getiterator(): - if self.verbosity >= 3: - self.dump_elem(elem) - menu = getmenu(elem.tag) - if menu: - attr, func = menu - value = func(elem.text) - props[attr] = value - self.bk.user_name = props.get('last_modified_by') or props.get('creator') - self.bk.props = props - if self.verbosity >= 2: - fprintf(self.logfile, "props: %r\n", props) - self.finish_off() - - def process_rels(self, stream): - if self.verbosity >= 2: - fprintf(self.logfile, "\n=== Relationships ===\n") - tree = ET.parse(stream) - r_tag = U_PKGREL + 'Relationship' - for elem in tree.findall(r_tag): - rid = elem.get('Id') - target = elem.get('Target') - reltype = elem.get('Type').split('/')[-1] - if self.verbosity >= 2: - self.dumpout('Id=%r Type=%r Target=%r', rid, reltype, target) - self.relid2reltype[rid] = reltype - # self.relid2path[rid] = 'xl/' + target - if target.startswith('/'): - self.relid2path[rid] = target[1:] # drop the / - else: - self.relid2path[rid] = 'xl/' + target - - def do_defined_name(self, elem): - #### UNDER CONSTRUCTION #### - if 0 and self.verbosity >= 3: - self.dump_elem(elem) - nobj = Name() - bk = self.bk - nobj.bk = bk - nobj.name_index = len(bk.name_obj_list) - bk.name_obj_list.append(nobj) - nobj.name = elem.get('name') - nobj.raw_formula = None # compiled bytecode formula -- not in XLSX - nobj.formula_text = cooked_text(self, elem) - map_attributes(_defined_name_attribute_map, elem, nobj) - if nobj.scope is None: - nobj.scope = -1 # global - if nobj.name.startswith("_xlnm."): - nobj.builtin = 1 - if self.verbosity >= 2: - nobj.dump(header='=== Name object ===') - - def do_defined_names(self, elem): - for child in elem: - self.do_defined_name(child) - make_name_access_maps(self.bk) - - def do_sheet(self, elem): - bk = self.bk - sheetx = bk.nsheets - # print elem.attrib - rid = elem.get(U_ODREL + 'id') - sheetId = int(elem.get('sheetId')) - name = unescape(ensure_unicode(elem.get('name'))) - reltype = self.relid2reltype[rid] - target = self.relid2path[rid] - if self.verbosity >= 2: - self.dumpout( - 'sheetx=%d sheetId=%r rid=%r type=%r name=%r', - sheetx, sheetId, rid, reltype, name) - if reltype != 'worksheet': - if self.verbosity >= 2: - self.dumpout('Ignoring sheet of type %r (name=%r)', reltype, name) - return - state = elem.get('state') - visibility_map = { - None: 0, - 'visible': 0, - 'hidden': 1, - 'veryHidden': 2 - } - bk._sheet_visibility.append(visibility_map[state]) - sheet = Sheet(bk, position=None, name=name, number=sheetx) - sheet.utter_max_rows = X12_MAX_ROWS - sheet.utter_max_cols = X12_MAX_COLS - bk._sheet_list.append(sheet) - bk._sheet_names.append(name) - bk.nsheets += 1 - self.sheet_targets.append(target) - self.sheetIds.append(sheetId) - - - def do_workbookpr(self, elem): - datemode = cnv_xsd_boolean(elem.get('date1904')) - if self.verbosity >= 2: - self.dumpout('datemode=%r', datemode) - self.bk.datemode = datemode - - tag2meth = { - 'definedNames': do_defined_names, - 'workbookPr': do_workbookpr, - 'sheet': do_sheet, - } - augment_keys(tag2meth, U_SSML12) - -class X12SST(X12General): - - def __init__(self, bk, logfile=DLF, verbosity=0): - self.bk = bk - self.logfile = logfile - self.verbosity = verbosity - if ET_has_iterparse: - self.process_stream = self.process_stream_iterparse - else: - self.process_stream = self.process_stream_findall - - def process_stream_iterparse(self, stream, heading=None): - if self.verbosity >= 2 and heading is not None: - fprintf(self.logfile, "\n=== %s ===\n", heading) - si_tag = U_SSML12 + 'si' - elemno = -1 - sst = self.bk._sharedstrings - for event, elem in ET.iterparse(stream): - if elem.tag != si_tag: continue - elemno = elemno + 1 - if self.verbosity >= 3: - fprintf(self.logfile, "element #%d\n", elemno) - self.dump_elem(elem) - result = get_text_from_si_or_is(self, elem) - sst.append(result) - elem.clear() # destroy all child elements - if self.verbosity >= 2: - self.dumpout('Entries in SST: %d', len(sst)) - if self.verbosity >= 3: - for x, s in enumerate(sst): - fprintf(self.logfile, "SST x=%d s=%r\n", x, s) - - def process_stream_findall(self, stream, heading=None): - if self.verbosity >= 2 and heading is not None: - fprintf(self.logfile, "\n=== %s ===\n", heading) - self.tree = ET.parse(stream) - si_tag = U_SSML12 + 'si' - elemno = -1 - sst = self.bk._sharedstrings - for elem in self.tree.findall(si_tag): - elemno = elemno + 1 - if self.verbosity >= 3: - fprintf(self.logfile, "element #%d\n", elemno) - self.dump_elem(elem) - result = get_text_from_si_or_is(self, elem) - sst.append(result) - if self.verbosity >= 2: - self.dumpout('Entries in SST: %d', len(sst)) - -class X12Styles(X12General): - - def __init__(self, bk, logfile=DLF, verbosity=0): - self.bk = bk - self.logfile = logfile - self.verbosity = verbosity - self.xf_counts = [0, 0] - self.xf_type = None - self.fmt_is_date = {} - for x in list(range(14, 23)) + list(range(45, 48)): #### hard-coding FIX ME #### - self.fmt_is_date[x] = 1 - # dummy entry for XF 0 in case no Styles section - self.bk._xf_index_to_xl_type_map[0] = 2 - # fill_in_standard_formats(bk) #### pre-integration kludge - - def do_cellstylexfs(self, elem): - self.xf_type = 0 - - def do_cellxfs(self, elem): - self.xf_type = 1 - - def do_numfmt(self, elem): - formatCode = ensure_unicode(elem.get('formatCode')) - numFmtId = int(elem.get('numFmtId')) - is_date = is_date_format_string(self.bk, formatCode) - self.fmt_is_date[numFmtId] = is_date - fmt_obj = Format(numFmtId, is_date + 2, formatCode) - self.bk.format_map[numFmtId] = fmt_obj - if self.verbosity >= 3: - self.dumpout('numFmtId=%d formatCode=%r is_date=%d', numFmtId, formatCode, is_date) - - def do_xf(self, elem): - if self.xf_type != 1: - #### ignoring style XFs for the moment - return - xfx = self.xf_counts[self.xf_type] - self.xf_counts[self.xf_type] = xfx + 1 - xf = XF() - self.bk.xf_list.append(xf) - self.bk.xfcount += 1 - numFmtId = int(elem.get('numFmtId', '0')) - xf.format_key = numFmtId - is_date = self.fmt_is_date.get(numFmtId, 0) - self.bk._xf_index_to_xl_type_map[xfx] = is_date + 2 - if self.verbosity >= 3: - self.dumpout( - 'xfx=%d numFmtId=%d', - xfx, numFmtId, - ) - self.dumpout(repr(self.bk._xf_index_to_xl_type_map)) - - tag2meth = { - 'cellStyleXfs': do_cellstylexfs, - 'cellXfs': do_cellxfs, - 'numFmt': do_numfmt, - 'xf': do_xf, - } - augment_keys(tag2meth, U_SSML12) - -class X12Sheet(X12General): - - def __init__(self, sheet, logfile=DLF, verbosity=0): - self.sheet = sheet - self.logfile = logfile - self.verbosity = verbosity - self.rowx = -1 # We may need to count them. - self.bk = sheet.book - self.sst = self.bk._sharedstrings - self.merged_cells = sheet.merged_cells - self.warned_no_cell_name = 0 - self.warned_no_row_num = 0 - if ET_has_iterparse: - self.process_stream = self.own_process_stream - - def own_process_stream(self, stream, heading=None): - if self.verbosity >= 2 and heading is not None: - fprintf(self.logfile, "\n=== %s ===\n", heading) - getmethod = self.tag2meth.get - row_tag = U_SSML12 + "row" - self_do_row = self.do_row - for event, elem in ET.iterparse(stream): - if elem.tag == row_tag: - self_do_row(elem) - elem.clear() # destroy all child elements (cells) - elif elem.tag == U_SSML12 + "dimension": - self.do_dimension(elem) - elif elem.tag == U_SSML12 + "mergeCell": - self.do_merge_cell(elem) - self.finish_off() - - def process_comments_stream(self, stream): - root = ET.parse(stream).getroot() - author_list = root[0] - assert author_list.tag == U_SSML12 + 'authors' - authors = [elem.text for elem in author_list] - comment_list = root[1] - assert comment_list.tag == U_SSML12 + 'commentList' - cell_note_map = self.sheet.cell_note_map - from .sheet import Note - text_tag = U_SSML12 + 'text' - r_tag = U_SSML12 + 'r' - t_tag = U_SSML12 + 't' - for elem in comment_list.findall(U_SSML12 + 'comment'): - ts = elem.findall('./' + text_tag + '/' + t_tag) - ts += elem.findall('./' + text_tag + '/' + r_tag + '/' + t_tag) - ref = elem.get('ref') - note = Note() - note.author = authors[int(elem.get('authorId'))] - note.rowx, note.colx = coords = cell_name_to_rowx_colx(ref) - note.text = '' - for t in ts: - note.text += cooked_text(self, t) - cell_note_map[coords] = note - - def do_dimension(self, elem): - ref = elem.get('ref') # example: "A1:Z99" or just "A1" - if ref: - # print >> self.logfile, "dimension: ref=%r" % ref - last_cell_ref = ref.split(':')[-1] # example: "Z99" - rowx, colx = cell_name_to_rowx_colx(last_cell_ref) - self.sheet._dimnrows = rowx + 1 - self.sheet._dimncols = colx + 1 - - def do_merge_cell(self, elem): - # The ref attribute should be a cell range like "B1:D5". - ref = elem.get('ref') - if ref: - first_cell_ref, last_cell_ref = ref.split(':') - first_rowx, first_colx = cell_name_to_rowx_colx(first_cell_ref) - last_rowx, last_colx = cell_name_to_rowx_colx(last_cell_ref) - self.merged_cells.append((first_rowx, last_rowx + 1, - first_colx, last_colx + 1)) - - def do_row(self, row_elem): - - def bad_child_tag(child_tag): - raise Exception('cell type %s has unexpected child <%s> at rowx=%r colx=%r' % (cell_type, child_tag, rowx, colx)) - - row_number = row_elem.get('r') - if row_number is None: # Yes, it's optional. - self.rowx += 1 - explicit_row_number = 0 - if self.verbosity and not self.warned_no_row_num: - self.dumpout("no row number; assuming rowx=%d", self.rowx) - self.warned_no_row_num = 1 - else: - self.rowx = int(row_number) - 1 - explicit_row_number = 1 - assert 0 <= self.rowx < X12_MAX_ROWS - rowx = self.rowx - colx = -1 - if self.verbosity >= 3: - self.dumpout(" row_number=%r rowx=%d explicit=%d", - row_number, self.rowx, explicit_row_number) - letter_value = _UPPERCASE_1_REL_INDEX - for cell_elem in row_elem: - cell_name = cell_elem.get('r') - if cell_name is None: # Yes, it's optional. - colx += 1 - if self.verbosity and not self.warned_no_cell_name: - self.dumpout("no cellname; assuming rowx=%d colx=%d", rowx, colx) - self.warned_no_cell_name = 1 - else: - # Extract column index from cell name - # A => 0, Z =>25, AA => 26, XFD => 16383 - colx = 0 - charx = -1 - try: - for c in cell_name: - charx += 1 - if c == '$': - continue - lv = letter_value[c] - if lv: - colx = colx * 26 + lv - else: # start of row number; can't be '0' - colx = colx - 1 - assert 0 <= colx < X12_MAX_COLS - break - except KeyError: - raise Exception('Unexpected character %r in cell name %r' % (c, cell_name)) - if explicit_row_number and cell_name[charx:] != row_number: - raise Exception('cell name %r but row number is %r' % (cell_name, row_number)) - xf_index = int(cell_elem.get('s', '0')) - cell_type = cell_elem.get('t', 'n') - tvalue = None - formula = None - if cell_type == 'n': - # n = number. Most frequent type. - # child contains plain text which can go straight into float() - # OR there's no text in which case it's a BLANK cell - for child in cell_elem: - child_tag = child.tag - if child_tag == V_TAG: - tvalue = child.text - elif child_tag == F_TAG: - formula = cooked_text(self, child) - else: - raise Exception('unexpected tag %r' % child_tag) - if not tvalue: - if self.bk.formatting_info: - self.sheet.put_cell(rowx, colx, XL_CELL_BLANK, '', xf_index) - else: - self.sheet.put_cell(rowx, colx, None, float(tvalue), xf_index) - elif cell_type == "s": - # s = index into shared string table. 2nd most frequent type - # child contains plain text which can go straight into int() - for child in cell_elem: - child_tag = child.tag - if child_tag == V_TAG: - tvalue = child.text - elif child_tag == F_TAG: - # formula not expected here, but gnumeric does it. - formula = child.text - else: - bad_child_tag(child_tag) - if not tvalue: - # - if self.bk.formatting_info: - self.sheet.put_cell(rowx, colx, XL_CELL_BLANK, '', xf_index) - else: - value = self.sst[int(tvalue)] - self.sheet.put_cell(rowx, colx, XL_CELL_TEXT, value, xf_index) - elif cell_type == "str": - # str = string result from formula. - # Should have (formula) child; however in one file, all text cells are str with no formula. - # child can contain escapes - for child in cell_elem: - child_tag = child.tag - if child_tag == V_TAG: - tvalue = cooked_text(self, child) - elif child_tag == F_TAG: - formula = cooked_text(self, child) - else: - bad_child_tag(child_tag) - # assert tvalue is not None and formula is not None - # Yuk. Fails with file created by gnumeric -- no tvalue! - self.sheet.put_cell(rowx, colx, XL_CELL_TEXT, tvalue, xf_index) - elif cell_type == "b": - # b = boolean - # child contains "0" or "1" - # Maybe the data should be converted with cnv_xsd_boolean; - # ECMA standard is silent; Excel 2007 writes 0 or 1 - for child in cell_elem: - child_tag = child.tag - if child_tag == V_TAG: - tvalue = child.text - elif child_tag == F_TAG: - formula = cooked_text(self, child) - else: - bad_child_tag(child_tag) - self.sheet.put_cell(rowx, colx, XL_CELL_BOOLEAN, int(tvalue), xf_index) - elif cell_type == "e": - # e = error - # child contains e.g. "#REF!" - for child in cell_elem: - child_tag = child.tag - if child_tag == V_TAG: - tvalue = child.text - elif child_tag == F_TAG: - formula = cooked_text(self, child) - else: - bad_child_tag(child_tag) - value = error_code_from_text[tvalue] - self.sheet.put_cell(rowx, colx, XL_CELL_ERROR, value, xf_index) - elif cell_type == "inlineStr": - # Not expected in files produced by Excel. - # Only possible child is . - # It's a way of allowing 3rd party s/w to write text (including rich text) cells - # without having to build a shared string table - for child in cell_elem: - child_tag = child.tag - if child_tag == IS_TAG: - tvalue = get_text_from_si_or_is(self, child) - else: - bad_child_tag(child_tag) - assert tvalue is not None - self.sheet.put_cell(rowx, colx, XL_CELL_TEXT, tvalue, xf_index) - else: - raise Exception("Unknown cell type %r in rowx=%d colx=%d" % (cell_type, rowx, colx)) - - tag2meth = { - 'row': do_row, - } - augment_keys(tag2meth, U_SSML12) - -def open_workbook_2007_xml( - zf, - component_names, - logfile=sys.stdout, - verbosity=0, - use_mmap=0, - formatting_info=0, - on_demand=0, - ragged_rows=0, - ): - ensure_elementtree_imported(verbosity, logfile) - bk = Book() - bk.logfile = logfile - bk.verbosity = verbosity - bk.formatting_info = formatting_info - if formatting_info: - raise NotImplementedError("formatting_info=True not yet implemented") - bk.use_mmap = False #### Not supported initially - bk.on_demand = on_demand - if on_demand: - if verbosity: - print("WARNING *** on_demand=True not yet implemented; falling back to False", file=bk.logfile) - bk.on_demand = False - bk.ragged_rows = ragged_rows - - x12book = X12Book(bk, logfile, verbosity) - zflo = zf.open('xl/_rels/workbook.xml.rels') - x12book.process_rels(zflo) - del zflo - zflo = zf.open('xl/workbook.xml') - x12book.process_stream(zflo, 'Workbook') - del zflo - props_name = 'docProps/core.xml' - if props_name in component_names: - zflo = zf.open(props_name) - x12book.process_coreprops(zflo) - - x12sty = X12Styles(bk, logfile, verbosity) - if 'xl/styles.xml' in component_names: - zflo = zf.open('xl/styles.xml') - x12sty.process_stream(zflo, 'styles') - del zflo - else: - # seen in MS sample file MergedCells.xlsx - pass - - sst_fname = 'xl/sharedStrings.xml' - x12sst = X12SST(bk, logfile, verbosity) - if sst_fname in component_names: - zflo = zf.open(sst_fname) - x12sst.process_stream(zflo, 'SST') - del zflo - - for sheetx in range(bk.nsheets): - fname = x12book.sheet_targets[sheetx] - zflo = zf.open(fname) - sheet = bk._sheet_list[sheetx] - x12sheet = X12Sheet(sheet, logfile, verbosity) - heading = "Sheet %r (sheetx=%d) from %r" % (sheet.name, sheetx, fname) - x12sheet.process_stream(zflo, heading) - del zflo - comments_fname = 'xl/comments%d.xml' % (sheetx + 1) - if comments_fname in component_names: - comments_stream = zf.open(comments_fname) - x12sheet.process_comments_stream(comments_stream) - del comments_stream - - sheet.tidy_dimensions() - - return bk diff --git a/wsgi.py b/wsgi.py index 65081c8e..50e53043 100644 --- a/wsgi.py +++ b/wsgi.py @@ -1,4 +1,4 @@ -from django.core.wsgi import get_wsgi_application from dj_static import Cling +from django.core.wsgi import get_wsgi_application application = Cling(get_wsgi_application())