[
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\nopen_collective: tabulapdf\n\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "on:\n  release:\n    types: [published]\npermissions:\n  contents: read\n  packages: write\njobs:\n  release:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: docker/login-action@v2\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ github.token }}\n      - uses: docker/build-push-action@v4\n        with:\n          push: true\n          tags: |\n            ghcr.io/${{ github.repository }}:${{ github.ref_name }}\n            ghcr.io/${{ github.repository }}:latest\n"
  },
  {
    "path": ".gitignore",
    "content": "static/pdfs\nlocal_settings.rb\ntabula.war\n.sass-cache\n\nlib/jars/javacv*\n.ruby-gemset\n\nTEST_PDFS\n.DS_Store\nbuild/Tabula.app\nbuild/tabula.jar\nbuild/tabula-*.zip\nbuild/mac\nbuild/windows\nbuild/tabula\nlaunch4j/\n\n# Based on https://github.com/github/gitignore/blob/master/Ruby.gitignore\n*.gem\n*.rbc\n*.swp\n.bundle\n.config\n.DS_store\ncoverage\nInstalledFiles\nlib/bundler/man\npkg\nrdoc\nspec/reports\ntest/tmp\ntest/version_tmp\ntmp\n"
  },
  {
    "path": ".ruby-version",
    "content": "jruby-9.2.13.0\n"
  },
  {
    "path": ".travis.yml",
    "content": "sudo: false\nlanguage: ruby\ndist: trusty\nbefore_install:\n  - gem update --system\n  - gem install bundler\n  - gem install jbundler\nrvm:\n  - jruby-9.1.9.0\njdk:\n  - oraclejdk8\n  - openjdk7\nscript: bundle exec jbundle install && bundle exec rake war && bundle exec rake jardist\nnotifications:\n  email: false\n"
  },
  {
    "path": "AUTHORS.md",
    "content": "# Authors & Acknowledgments\n\nTabula was originally started by Manuel Aristarán in late 2012.\n\nThe PRIMARY AUTHORS are (and/or have been):\n\n* Manuel Aristarán - MIT Media Lab (formerly La Nación, Knight-Mozilla OpenNews)\n* Mike Tigas - ProPublica, Knight-Mozilla OpenNews\n* Jeremy B. Merrill - The New York Times (formerly ProPublica)\n* Jason Das, designer <http://jasondas.com>\n* David Frackman\n* Travis Swicegood - Texas Tribune\n\nSpecial thanks to these organizations:\n\n* Knight-Mozilla OpenNews <https://opennews.org/>\n* ProPublica <http://propublica.org>\n* La Nación <http://www.lanacion.com.ar>\n* The New York Times <http://www.nytimes.com>\n* Knight Lab at Northwestern University <http://knightlab.northwestern.edu/>\n* The John S. and James L. Knight Foundation <http://www.knightfoundation.org/>\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "CONTRIBUTING\n============\n\nTabula is an open-source project, which means it depends on volunteers to build and improve it.\n\nInterested in helping out? We'd love to have your help!\n\nYou can help by:\n\n- [Reporting a bug](https://github.com/tabulapdf/tabula/issues/new).\n- Adding or editing documentation.\n- Contributing code via a Pull Request from ideas listed in the [Enhancements](https://github.com/tabulapdf/tabula/labels/enhancement) section of the issues.\n- Spreading the word about Tabula to people who might be able to benefit from using it.\n\nDid you have a problem? Guidelines for reporting a bug\n------------------------------------------------------\n\nDid Tabula not work for you? We'd like to know about it. We'd also like to know if Tabula worked, but wasn't as easy or useful as it could be. Here's what you can tell us to so we can help you better.\n\n1. What error message did you get? (We need the whole thing! If it looks like gobbledygook to you, it's probably very useful to us. That's why it's there!)\n2. What steps did you take? The more precise, the better.\n3. What PDF were you trying to extract data from? Some PDFs are wacky, so seeing the exact PDF will be useful. We understand that sometimes PDFs are confidential. If you can share it, just not publicly, send us an email. If you cant', we understand, but might not be able to help you.\n4. What version of Tabula are you using? If you're using an older version, we may have solved the problem already.\n5. What platform are you on? Windows 7 or 8? Mac? Linux? If your computer uses a language other than English or Spanish, we'd like to know that too.\n\nGuidelines for contributing code\n--------------------------------\n\nIf you'd like to contribute code, here's some stuff you should know: You're also welcome to send us a note, if you'd like. All of our email addresses are listed on our Github pages.\n\nTabula comes in a bunch of parts, all located in the [TabulaPDF Github organization](https://github.com/tabulapdf). \n -The [tabula](https://github.com/tabulapdf/tabula) repo is the UI. We aim for it to soon be all front-end, but right now has a small web server, written in Ruby, to interface between the front-end and extractor library, called \"tabula-extractor\"\n - [tabula-java](https://github.com/tabulapdf/tabula-java/) is a pure Java port, for speed/wider usability. \n\nThe [Enhancements](https://github.com/tabulapdf/tabula/labels/enhancement) section of the issues lists some important improvements to Tabula that you could try out. They're well-suited to contributors, since they don't depend on a deep knowledge of all of Tabula's parts and they don't depend on close coordination.\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM jruby:9.2-jdk\n\nRUN apt-get update -qq && apt-get install -y build-essential git \\\n  && apt-get clean && rm -rf /var/lib/apt/lists/*\nRUN echo 'gem: --no-rdoc --no-ri' >> /.gemrc\n\nENV GEM_HOME /usr/local/bundle\nENV PATH $GEM_HOME/bin:$PATH\nRUN gem install bundler -v '< 2' \\\n  && bundle config --global path \"$GEM_HOME\" \\\n  && bundle config --global bin \"$GEM_HOME/bin\"\n\n# don't create \".bundle\" in all our apps\nENV BUNDLE_APP_CONFIG $GEM_HOME\n\nWORKDIR /app\nEXPOSE 9292\nCMD [\"jruby\", \"-G\", \"-r\", \"jbundler\", \"-S\", \"rackup\", \"-o\", \"0.0.0.0\", \"config.ru\"]\n\n# these didn't work as ONBUILD, strangely. Idk why. -JBM\nCOPY Gemfile Gemfile.lock Jarfile Jarfile.lock ./\nRUN bundle install && jruby -S jbundle install\nCOPY . .\n"
  },
  {
    "path": "Gemfile",
    "content": "#since war/jar bundle requires gem package; use gem-in-a-box for testing\n#or execute tabula via \"rackup\".\n#source \"http://127.0.0.1:9292\"\n\nsource \"https://rubygems.org\"\nplatform :jruby do\n  gem \"cuba\", \"~> 3.9.2\"\n  gem \"rack\", \">= 2.0.6\"\n  gem \"tilt\", \"~> 2.0.8\"\n\n  group :development do\n    gem 'jar-dependencies', '0.3.12'\n    gem 'jbundler', '~> 0.9.3'\n    gem \"rake\"\n    gem \"warbler\", \"~> 2.0.5\"\n    gem \"jruby-jars\", \"9.2.0.0\"\n    gem \"bootstrap-sass\", \">= 3.4.1\"\n    gem \"compass\"\n  end\nend\n"
  },
  {
    "path": "Jarfile",
    "content": "jar 'technology.tabula:tabula', '1.0.4'"
  },
  {
    "path": "LICENSE.md",
    "content": "Copyright (C) 2012-2020 Manuel Aristarán <jazzido@jazzido.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "NOTICE.txt",
    "content": "Tabula\n© 2012-2020 Manuel Aristarán. Available under MIT License. See `AUTHORS.md`\nand `LICENSE.md`.\n\nThis product includes software (lib/pdfbox-app-1.8.0.jar) developed at\nThe Apache Software Foundation (http://www.apache.org/).\n"
  },
  {
    "path": "README.md",
    "content": "**Is `tabula` an active project?**\n\nTabula is, and always has been, a volunteer-run project. We've occasionally had funding for specific features, but it's never been a commercial undertaking. At the moment, none of the original authors have the time to actively work on the project. The end-user application, hosted on this repo, is unlikely to see updates from us in the near future. [`tabula-java`](https://github.com/tabulapdf/tabula-java) sees updates and occasional bug-fix releases from time to time.\n\n--\n\n**Repo Note**: The `master` branch is an *in development* version of Tabula. This may be substantially different from the latest [releases of Tabula](https://github.com/tabulapdf/tabula/releases).\n\n---\n\n\n\n# Tabula\n\n[tabula `master`](https://github.com/tabulapdf/tabula/tree/master)\n[![Build Status](https://travis-ci.org/tabulapdf/tabula.svg?branch=master)](https://travis-ci.org/tabulapdf/tabula)  \n\nTabula helps you liberate data tables trapped inside PDF files.\n\n* [Download from the official site](http://tabula.technology/)\n* [Read more about Tabula on OpenNews Source](https://source.opennews.org/en-US/articles/introducing-tabula/)\n* Interested in using Tabula on the command-line? Check out [tabula-java](https://github.com/tabulapdf/tabula-java), a Java library and command-line interface for Tabula. (This is the extraction library that powers Tabula.)\n\n© 2012-2020 Manuel Aristarán. Available under MIT License. See\n[`AUTHORS.md`](AUTHORS.md) and [`LICENSE.md`](LICENSE.md).\n\n-   [Why Tabula?](#why-tabula)\n-   [Using Tabula](#using-tabula)\n-   [Known issues](#known-issues)\n-   [Incorporating Tabula into your own\n    project](#incorporating-tabula-into-your-own-project)\n-   [Running Tabula from source\n    (for developers)](#running-tabula-from-source-for-developers)\n    -   [Building a packaged application\n        version](#building-a-packaged-application-version)\n-   [Contributing](#contributing)\n    -   [Backers](#backers)\n\n## Why Tabula?\n\nIf you’ve ever tried to do anything with data provided to you in PDFs, you\nknow how painful this is — you can’t easily copy-and-paste rows of data out\nof PDF files. Tabula allows you to extract that data in CSV format, through\na simple web interface.\n\n**Caveat**: Tabula only works on text-based PDFs, not scanned documents. If you can click-and-drag to select text in your table in a PDF viewer (even if the output is disorganized trash), then your PDF is text-based and Tabula should work.\n\n**Security Concerns?**: Tabula is designed with security in mind. Your PDF and the extracted data *never* touch the net -- when you use Tabula on your local machine, as long as your browser's URL bar says \"localhost\" or \"127.0.0.1\", all processing takes place on your local machine. Other than to retrieve a few badges and other static assets, there are two calls that are made from your browser to external machines; one fetches the list of latest Tabula versions from GitHub to alert you if Tabula has been updated, the other makes a call to a stats counter that helps us determine how often various versions of Tabula are being used. If this is a problem, the version check can be disabled by adding `-Dtabula.disable_version_check=1` to the command line at startup, and the stats counter call can be disabled by adding `-Dtabula.disable_notifications=1`. Please note: If you are providing Tabula as a service using a reverse SSL proxy, users [may notice a security warning](https://github.com/tabulapdf/tabula/issues/924) due to our stats counter endpoint being hosted at a non-secure URL, so you may wish to disable the notifications in this scenario.\n\n## Using Tabula\n\nFirst, make sure you have a recent copy of Java installed. You can\n[download Java here][jre_download]. Tabula requires\na Java Runtime Environment compatible with Java 7 (i.e. Java 7, 8 or higher).\nIf you have a problem, check [Known Issues](#knownissues) first, then [report an issue](http://www.github.com/tabulapdf/tabula/issues).\n\n* ### Windows\n  Download `tabula-win.zip` from [the download site][tabula_dl]. Unzip the whole thing\n  and open the `tabula.exe` file inside. A browser should automatically open\n  to http://127.0.0.1:8080/ . If not, open your web browser of choice and\n  visit that link.\n\n  To close Tabula, just go back to the console window and press \"Control-C\"\n  (as if to copy).\n\n* ### Mac OS X\n  Download `tabula-mac.zip` from [the download site][tabula_dl]. Unzip and open\n  the Tabula app inside. A browser should automatically open\n  to http://127.0.0.1:8080/ . If not, open your web browser of choice and\n  visit that link.\n\n  To close Tabula, find the Tabula icon in your dock, right-click (or\n  control-click) on it, and press \"Quit\".\n\n  Note: If you’re running Mac OS X 10.8 or later, you might get an error like \"Tabula is damaged and can't be opened.\" We're working on fixing this, but click [here](#gatekeeper) for a workaround.\n\n* ### Linux snap\n  \n  Tabula is packaged as a snap package. If you have snap on your system, you can install it with\n\n  ```bash\n  sudo snap install tabula\n  ```\n\n* ### Other platforms (e.g. Linux)\n\n  Download `tabula-jar.zip` from [the download site][tabula_dl] and unzip it\n  to the directory of your choice. Open a terminal window, and `cd` to inside\n  the `tabula` directory you just unzipped. Then run:\n\n  `java -Dfile.encoding=utf-8 -Xms256M -Xmx1024M -jar tabula.jar`\n\n  Then manually navigate your browser to http://127.0.0.1:8080/ (New in\n  Tabula 1.1. To go back to the old behavior that automatically launches\n  your web browser, use the `-Dtabula.openBrowser=true` option.\n\n  Tabula binds to port 8080 by default. You can change it with the `warbler.port` option; for example, to use port 9999:\n\n  `java -Dfile.encoding=utf-8 -Xms256M -Xmx1024M -Dwarbler.port=9999 -jar tabula.jar`\n\n* ### [Docker Compose](https://docs.docker.com/compose/) quick start using [Amazon Correttto](https://github.com/corretto) image\n  Make a new directory e.g. `tabulapdf` and enter it.\n  \n  `mkdir -p /opt/docker/tabulapdf`\n  `cd /opt/docker/tabulapdf`\n  \n  Download tabula-jar package - for example version 1.2.1\n  \n  `wget https://github.com/tabulapdf/tabula/releases/download/v1.2.1/tabula-jar-1.2.1.zip`\n  \n  verify checksum (compare output with the release page)\n\n  `sha256sum tabula-jar-1.2.1.zip`\n  \n  and unzip it.\n  \n  `unzip tabula-jar-1.2.1.zip`\n  \n  Place or create a `docker-compose.yml` file, adjust accordingly\n  \n  ```\n  ### tabulapdf docker-compose.yml example ###\n  services:\n  tabulapdf:\n    image: amazoncorretto:17\n    container_name: tabulapdf-app\n    command: >\n      java -Dfile.encoding=utf-8 -Xms256M -Xmx1024M -Dwarbler.port=8080 -Dtabula.openBrowser=false -jar /app/tabula.jar\n    volumes:\n      - ./tabula:/app\n    ports:\n      - \"8080:8080\"\n  ```\n  \n  Run the app with\n  \n  `docker compose up -d`\n  \n  The app will be exposed on port 8080 and can be easily paired with a reverse proxy e.g. traefik\n\nIf the program fails to run, double-check that you have [Java installed][jre_download]\nand then try again.\n\n[jre_download]: https://www.java.com/download/\n[tabula_dl]: http://tabula.technology\n\n\n\n## <a name=\"knownissues\">Known issues</a>\n\nThere are some bugs that we're aware of that we haven't managed to fix yet. If there's not a solution here or you need more help, please go ahead and [report an issue](http://www.github.com/tabulapdf/tabula/issues).\n\n\n* <a name='legacy'>**Legacy Java Environment (SE 6) Is Required:**</a> (Mac):\n  The Mac operating system recently changed how it packages the Java Runtime Environment. If you get this error, download Tabula's [\"large experimental\" package](https://github.com/tabulapdf/tabula/releases/download/v0.9.7/tabula-mac-0.9.7-large-experimental.zip). This package includes its own Java Runtime Environment and should work without this issue.\n\n* <a name='gatekeeper'>**\"Tabula is damaged and can't be opened\"** (Mac)</a>:\n  If you’re running Mac OS X 10.8 or later, GateKeeper may prevent you from opening\n  the Tabula app. Please [see this GateKeeper page][gatekeeper] for more information.\n\n  1. Right-click on Tabula.app and select Open from the context menu.\n  2. The system will tell you that the application is \"from an unidentified developer\" and ask you whether you want to open it. Click Open to allow the application to run. The system remembers this choice and won't prompt you again.\n\n  (If you continue to have issues, double-check the [OS X GateKeeper documentation][gatekeeper] for more information.)\n\n[gatekeeper]: http://support.apple.com/kb/HT5290\n\n* <a name='encoding'>**org.jruby.exceptions.RaiseException: (Encoding::CompatibilityError) incompatible character encodings:**</a> (Windows):\n  Your Windows computer expects a type of encoding other than Unicode or Windows's English encoding. You can fix this by entering a few simple commands in the Command Prompt. (The commands won't affect anything besides Tabula.)\n\n  1. Open a Command Prompt\n  2. type `cd` and then the path to the directory that contains `tabula.exe`, e.g. `cd C:\\Users\\Username\\Downloads`\n  3. Change that terminal's codepage to Unicode by typing: `chcp 65001`\n  4. Run Tabula by typing `tabula.exe`\n\n* <a name='portproblems'>**A browser tab opens, but something other than Tabula loads there. Or Tabula doesn't start.**</a>\n  It's possible another program is using port 8080, which Tabula binds to by default. You can try closing the other program, or change the port Tabula uses by running Tabula from the terminal with the `warbler.port` property:\n\n  `java -Dfile.encoding=utf-8 -Xms256M -Xmx1024M -Dwarbler.port=9999 -jar tabula.jar`\n\n## Incorporating Tabula into your own project\n\nTabula is open-source, so we'd love for you to incorporate pieces of Tabula into your own projects. The \"guts\" of Tabula -- that is, the logic and heuristics that reconstruct tables from PDFs -- is contained in the [tabula-java](https://github.com/tabulapdf/tabula-java/) repo. There's a JAR file that you can easily incorporate into JVM languages like Java, Scala or Clojure and it includes a command-line tool for you to automate your extraction tasks. Visit that repo for more information on how to use `tabula-java` on the CLI and on how Tabula exports `tabula-java` scripts.\n\n### Bindings:\n\nTabula has bindings for JRuby and R. If you end up writing bindings for another language, let us know and we'll add a link here.\n\n - [tabulizer](https://github.com/leeper/tabulizer) provides [R](https://www.r-project.org/) bindings for tabula-java and is community-supported by [@leeper](https://github.com/leeper).\n - [tabula-js](https://github.com/ezodude/tabula-js) provides [Node.js](https://nodejs.org/en/) bindings for tabula-java; it is community-supported by [@ezodude](https://github.com/ezodude).\n - [tabula-py](https://github.com/chezou/tabula-py) provides [Python](https://python.org) bindings for tabula-java; it is community-supported by [@chezou](https://github.com/chezou).\n - [tabula-extractor](https://github.com/tabulapdf/tabula-extractor/) *DEPRECATED* - Provides JRuby bindings for tabula-java\n\n\n\n\n## Running Tabula from source (for developers)\n\n1. Download JRuby. You can install it from its website, or using tools like\n   `rvm` or `rbenv`. Note that as of Tabula 1.1.0 (7875582becb2799b65586d5680782cafd399bb33), Tabula uses the JRuby 9000 series (i.e. JRuby 9.1.5.0).\n\n2. Download Tabula and install the Ruby dependencies. (Note: if using `rvm` or\n   `rbenv`, ensure that JRuby is being used.\n\n    ~~~\n    git clone git://github.com/tabulapdf/tabula.git\n    cd tabula\n\n    gem install bundler -v 1.17.3\n    bundle install\n    jruby -S jbundle install\n    ~~~\n\n**Then, start the development server:**\n\n    jruby -G -r jbundler -S rackup\n\n(If you get encoding errors, set the `JAVA_OPTS` environment variable to `-Dfile.encoding=utf-8`)\n\nThe site instance should now be viewable at http://127.0.0.1:9292/ .\n\nYou can a couple some options when executing the server in this manner:\n\n    TABULA_DATA_DIR=\"/tmp/tabula\" \\\n    TABULA_DEBUG=1 \\\n    jruby -G -r jbundler -S rackup\n\n* `TABULA_DATA_DIR` controls where uploaded data for Tabula is stored. By default,\n  data is stored in the OS-dependent application data directory for the current\n  user. (similar to: `C:\\Users\\foo\\AppData\\Roaming\\Tabula` on Windows,\n  `~/Library/Application Support/Tabula` on Mac, `~/.tabula` on Linux/UNIX)\n* `TABULA_DEBUG` prints out extra status data when PDF files are being processed.\n   (`false` by default.)\n\n**Alternatively, running the server as a JAR file**\n\nTesting in this manner will be closer to testing the \"packaged application\"\nversion of the app.\n\n    jruby -G -S rake war\n    java -Dfile.encoding=utf-8 -Xms256M -Xmx1024M -jar build/tabula.jar\n\n\nIf you intend to develop against an unreleased version of [`tabula-java`](https://github.com/tabulapdf/tabula-java), you need to install its JAR to your local Maven repository. From the directory that contains `tabula-java` source:\n\n    mvn install:install-file -Dfile=target/tabula-<version>-SNAPSHOT.jar -DgroupId=technology.tabula -DartifactId=tabula -Dversion=<version>-SNAPSHOT -Dpackaging=jar -DpomFile=pom.xml\n\nThen, adjust the `Jarfile` accordingly.\n\n### Building a packaged application version\n\nAfter performing the above steps (\"Running Tabula from source\"), you can compile\nTabula into a standalone application:\n\n**Mac OS X**\n\nIf you wish to share Tabula with other machines, you will need a codesigning certificate.\nOur distribution of Tabula uses a self-signed certificate, as noted above. See\n[this section of build.xml][buildxml_cert] for details. If you will only be running Tabula\non the machine you are building it on, you may remove this entire <exec> block (lines 44-53).\n\nTo compile the app:\n\n    WEBSERVER_VERSION=9.4.31.v20200723 MAVEN_REPO=https://repo1.maven.org/maven2 rake macosx\n\nThis will result in a portable \"tabula_mac.zip\" archive (inside the `build` directory)\nfor Mac OS X users.\n\nNote that the Mac version bundles Java with the Tabula app.\nThis results in a 98MB zip file, versus the 30MB zip file for other platforms,\nbut allows users to run Tabula without having to worry about [Java version\nincompatibilities](https://github.com/tabulapdf/tabula/issues/237).\n\n[buildxml_cert]: https://github.com/tabulapdf/tabula/blob/master/build.xml#L44-53\n\n**Windows**\n\nYou can build .exe files for the Windows target on any platform.\n\nDownload a [3.1.X (beta) copy of Launch4J][launch4j].\n\nUnzip it into the Tabula repo so that \"launch4j\" (with subdirectories \"bin\", etc.)\nis in the repository root.\n\n(If you're building on a 64bit Linux, you may need to install 32bit libs like, in Ubuntu `sudo apt-get install lib32z1 lib32ncurses5`)\n\n\nThen:\n\n    WEBSERVER_VERSION=9.4.31.v20200723 MAVEN_REPO=https://repo1.maven.org/maven2 rake windows\n\nThis will result in a portable \"tabula_win.zip\" archive (inside the `build` directory)\nfor Mac OS X users.\n\n---\n\nIf you have issues, you can try building manually. (These commands are for\nOS X/Linux and may need to be adjusted for Windows users.)\n\n    # (from the root directory of the repo)\n    WEBSERVER_VERSION=9.4.31.v20200723 MAVEN_REPO=https://repo1.maven.org/maven2 rake war\n    cd launch4j\n    ant -f ../build.xml windows\n\nA \"tabula.exe\" file will be generated in \"build/windows\". To run, the exe file\nneeds \"tabula.jar\" (contained in \"build\") in the same directory. You can create a\n.zip archive by doing:\n\n    # (from the root directory of the repo)\n    cd build/windows\n    mkdir tabula\n    cp tabula.exe ./tabula/\n    cp ../tabula.jar ./tabula/\n    zip -r9 tabula_win.zip tabula\n    rm -fr tabula\n\n[launch4j]: http://sourceforge.net/projects/launch4j/files/launch4j-3/3.1.0-beta1/\n\n## Contributing\n\nInterested in helping out? We'd love to have your help!\n\nYou can help by:\n\n- [Reporting a bug](https://github.com/tabulapdf/tabula/issues).\n- Adding or editing documentation.\n- Contributing code via a Pull Request from ideas or bugs listed in the [Enhancements](https://github.com/tabulapdf/tabula/labels/enhancement) section of the issues. [see `CONTRIBUTING.md`](CONTRIBUTING.md)\n- Spreading the word about Tabula to people who might be able to benefit from using it.\n\n### Backers\n\nYou can also support our continued work on Tabula with a one-time or monthly donation [on OpenCollective](https://opencollective.com/tabulapdf#support). Organizations who use Tabula can also [sponsor the project](https://opencollective.com/tabulapdf#support) for acknowledgement on [our official site](http://tabula.technology/) and this README.\n\nTabula is made possible in part through <a href=\"https://opencollective.com/tabulapdf\">the generosity of our users</a> and through grants from the <a href=\"http://www.knightfoundation.org/\">Knight Foundation</a> and the <a href=\"https://shuttleworthfoundation.org/\">Shuttleworth Foundation</a>. Special thanks to all the users and organizations that support Tabula!\n\n<a href=\"https://opencollective.com/tabulapdf/backer/0/website\" target=\"_blank\"><img src=\"https://opencollective.com/tabulapdf/backer/0/avatar\"></a>\n<a href=\"https://opencollective.com/tabulapdf/backer/1/website\" target=\"_blank\"><img src=\"https://opencollective.com/tabulapdf/backer/1/avatar\"></a>\n<a href=\"https://opencollective.com/tabulapdf/backer/2/website\" target=\"_blank\"><img src=\"https://opencollective.com/tabulapdf/backer/2/avatar\"></a>\n<a href=\"https://opencollective.com/tabulapdf/backer/3/website\" target=\"_blank\"><img src=\"https://opencollective.com/tabulapdf/backer/3/avatar\"></a>\n<a href=\"https://opencollective.com/tabulapdf/backer/4/website\" target=\"_blank\"><img src=\"https://opencollective.com/tabulapdf/backer/4/avatar\"></a>\n<a href=\"https://opencollective.com/tabulapdf/backer/5/website\" target=\"_blank\"><img src=\"https://opencollective.com/tabulapdf/backer/5/avatar\"></a>\n\n<a title=\"The John S. and James L. Knight Foundation\" href=\"http://www.knightfoundation.org/\" target=\"_blank\"><img width=\"220\" alt=\"The John S. and James L. Knight Foundation\" src=\"http://www.knightfoundation.org/media/uploads/media_images/knight-logo-300.jpg\"></a>\n<a title=\"The Shuttleworth Foundation\" href=\"https://shuttleworthfoundation.org/\" target=\"_blank\"><img width=\"200\" alt=\"The Shuttleworth Foundation\" src=\"https://raw.githubusercontent.com/tabulapdf/tabula/gh-pages/shuttleworth.jpg\"></a>\n\nMore acknowledgments can be found in [`AUTHORS.md`](AUTHORS.md).\n"
  },
  {
    "path": "Rakefile",
    "content": "require 'fileutils'\nrequire 'warbler'\n\n########## java jar compilation ##########\n\nWarbler::Task.new(\"war\",\n  Warbler::Config.new { |config|\n    config.features = %w(executable)\n    config.jar_name = 'build/tabula'\n    config.jar_extension = 'jar'\n    config.webserver = \"jetty\"\n    config.webxml.jruby.compat.version = \"1.9\"\n    config.webxml.jruby.rack.logging = \"stderr\"\n    config.dirs = ['lib', 'webapp']\n    config.override_gem_home = false\n    config.init_contents << StringIO.new(\"\\nGem.clear_paths\\nGem.path\\n\\n\")\n  }\n)\n\n# version we're building\ndef build_version\n  ENV['TABULA_VERSION'] || \"rev#{`git rev-list --max-count=1 HEAD`.strip}\"\nend\n\ndef invoke_ant(*args)\n  IO.popen(\"ant #{args.join(' ')}\") { |f|\n    yield f\n  }\nend\n\n########## distribution bundles ##########\ntask :create_version_file do |t|\n  puts \"Creating version file (#{build_version})...\"\n  tabula_dir = File.expand_path(File.dirname(__FILE__))\n  rb_file = <<-eos\n    $TABULA_VERSION = \"#{build_version}\"\n  eos\n  File.open(File.join(tabula_dir, 'webapp', 'tabula_version.rb'), 'wb') do |f|\n    f.write rb_file\n  end\nend\n\ntask :delete_version_file do |t|\n  tabula_dir = File.expand_path(File.dirname(__FILE__))\n  FileUtils.rm(File.join(tabula_dir, 'webapp', 'tabula_version.rb'))\nend\n\n\ntask :jardist => [:create_version_file, :war] do |t|\n  tabula_dir = File.expand_path(File.dirname(__FILE__))\n  build_dir = File.join(tabula_dir, \"build\")\n  dist_dir = File.join(build_dir, \"jardist\", \"tabula\")\n\n  if File.exist?(File.join(build_dir, \"jardist\"))\n    FileUtils.rm_rf(File.join(build_dir, \"jardist\"))\n  end\n\n  puts \"\\n======================================================\"\n  puts \"Building jar zip file bundle...\"\n  puts \"======================================================\\n\\n\"\n\n  Dir.mkdir(File.join(build_dir, \"jardist\"))\n  Dir.mkdir(File.join(build_dir, \"jardist\", \"tabula\"))\n\n  jar_src = File.join(build_dir, \"tabula.jar\")\n  jar_dst = File.join(dist_dir, \"tabula.jar\")\n  FileUtils.cp(jar_src, jar_dst)\n\n  readme_src = File.join(build_dir, \"dist-README.txt\")\n  readme_dst = File.join(dist_dir, \"README.txt\")\n  FileUtils.cp(readme_src, readme_dst)\n\n  lic_src = File.join(build_dir, \"dist-LICENSE.txt\")\n  lic_dst = File.join(dist_dir, \"LICENSE.txt\")\n  FileUtils.cp(lic_src, lic_dst)\n\n  authors_src = File.join(tabula_dir, \"AUTHORS.md\")\n  authors_dst = File.join(dist_dir, \"AUTHORS.txt\")\n  FileUtils.cp(authors_src, authors_dst)\n\n  cd File.join(build_dir, \"jardist\")\n  output = File.join(build_dir, \"tabula-jar-#{build_version}.zip\")\n  if File.exists?(output)\n    File.delete(output)\n  end\n\n  IO.popen(\"zip -r9 #{output} tabula\") { |f|\n    f.each { |line| puts line }\n  }\n  FileUtils.rm_rf(dist_dir)\n  puts \"\\n======================================================\"\n  puts \"Zip file saved to #{output}\"\n  puts \"======================================================\\n\\n\"\nend\n\n\ntask :macosx => [:create_version_file, :war] do |t|\n  tabula_dir = File.expand_path(File.dirname(__FILE__))\n  build_dir = File.join(tabula_dir, \"build\")\n  dist_dir = File.join(build_dir, \"mac\", \"tabula\")\n\n  cd File.join(tabula_dir)\n\n  if File.exist?(File.join(build_dir, \"mac\"))\n    FileUtils.rm_rf(File.join(build_dir, \"mac\"))\n  end\n\n  puts \"\\n======================================================\"\n  puts \"Building Mac OS X app...\"\n  puts \"======================================================\\n\\n\"\n\n  invoke_ant(\"-Dfull_version=#{build_version}\", \"-v\", \"macbundle\") { |f|\n    f.each { |line| puts line }\n  }\n\n\n  puts \"\\n======================================================\"\n  puts \"Creating zip file bundle...\"\n  puts \"======================================================\\n\\n\"\n\n  Dir.mkdir(dist_dir)\n\n  app_src = File.join(build_dir, \"mac\", \"Tabula.app\")\n  app_dst = File.join(dist_dir, \"Tabula.app\")\n  FileUtils.mv(app_src, app_dst)\n\n  readme_src = File.join(build_dir, \"dist-README.txt\")\n  readme_dst = File.join(dist_dir, \"README.txt\")\n  FileUtils.cp(readme_src, readme_dst)\n\n  lic_src = File.join(build_dir, \"dist-LICENSE.txt\")\n  lic_dst = File.join(dist_dir, \"LICENSE.txt\")\n  FileUtils.cp(lic_src, lic_dst)\n\n  authors_src = File.join(tabula_dir, \"AUTHORS.md\")\n  authors_dst = File.join(dist_dir, \"AUTHORS.txt\")\n  FileUtils.cp(authors_src, authors_dst)\n\n  cd File.join(build_dir, \"mac\")\n  output = File.join(build_dir, \"tabula-mac-#{build_version}.zip\")\n  if File.exists?(output)\n    File.delete(output)\n  end\n\n  IO.popen(\"zip -r9 #{output} tabula\") { |f|\n    f.each { |line| puts line }\n  }\n  FileUtils.rm_rf(dist_dir)\n  puts \"\\n======================================================\"\n  puts \"Zip file saved to #{output}\"\n  puts \"======================================================\\n\\n\"\nend\n\n\ntask :windows => [:create_version_file, :war] do |t|\n  tabula_dir = File.expand_path(File.dirname(__FILE__))\n  build_dir = File.join(tabula_dir, \"build\")\n  dist_dir = File.join(build_dir, \"windows\", \"tabula\")\n\n  if File.exist?(File.join(build_dir, \"windows\"))\n    FileUtils.rm_rf(File.join(build_dir, \"windows\"))\n  end\n\n  cd File.join(tabula_dir)\n\n  puts \"\\n======================================================\"\n  puts \"Building Windows executable...\"\n  puts \"======================================================\\n\\n\"\n\n  # exe files REALLY need x.x.x.x otherwise the compile fails.\n  if build_version.start_with?('rev')\n    win_build_version = '0.0.0.0'\n  else\n    win_build_version = build_version\n    while win_build_version.split('.').length < 4\n      win_build_version = \"#{win_build_version}.0\"\n    end\n  end\n\n  cd File.join(File.expand_path(File.dirname(__FILE__)), \"launch4j\")\n  invoke_ant(\"-Dfull_version=#{win_build_version}\", \"-f\", \"../build.xml\", \"windows\") { |f|\n    f.each { |line| puts line }\n  }\n  puts \"\\n======================================================\"\n  puts \"Creating zip file bundle...\"\n  puts \"======================================================\\n\\n\"\n\n  Dir.mkdir(dist_dir)\n\n  app_src = File.join(build_dir, \"windows\", \"tabula.exe\")\n  app_dst = File.join(dist_dir, \"tabula.exe\")\n  FileUtils.mv(app_src, app_dst)\n\n  jar_src = File.join(build_dir, \"tabula.jar\")\n  jar_dst = File.join(dist_dir, \"tabula.jar\")\n  FileUtils.cp(jar_src, jar_dst)\n\n  readme_src = File.join(build_dir, \"dist-README.txt\")\n  readme_dst = File.join(dist_dir, \"README.txt\")\n  FileUtils.cp(readme_src, readme_dst)\n\n  lic_src = File.join(build_dir, \"dist-LICENSE.txt\")\n  lic_dst = File.join(dist_dir, \"LICENSE.txt\")\n  FileUtils.cp(lic_src, lic_dst)\n\n  authors_src = File.join(tabula_dir, \"AUTHORS.md\")\n  authors_dst = File.join(dist_dir, \"AUTHORS.txt\")\n  FileUtils.cp(authors_src, authors_dst)\n\n  cd File.join(build_dir, \"windows\")\n  output = File.join(build_dir, \"tabula-win-#{build_version}.zip\")\n  if File.exists?(output)\n    File.delete(output)\n  end\n\n  IO.popen(\"zip -r9 #{output} tabula\") { |f|\n    f.each { |line| puts line }\n  }\n  FileUtils.rm_rf(dist_dir)\n  puts \"\\n======================================================\"\n  puts \"Zip file saved to #{output}\"\n  puts \"======================================================\\n\\n\"\nend\n\ntask :build_all_platforms => [:create_version_file, :war] do |t|\n  ['jardist', 'macosx', 'windows'].each do |platform|\n    Rake::Task[platform].execute\n    puts\n  end\nend\n\n# delete version file after build\n['jardist', 'macosx', 'windows'].each do |t|\n  puts \"Deleting version file.\"\n  Rake::Task[t.intern].enhance {\n    Rake::Task['delete_version_file'.intern].invoke\n  }\nend\n"
  },
  {
    "path": "build/dist-LICENSE.txt",
    "content": "tabula and tabula-extractor\n\nCopyright (C) 2012-2020 Manuel Aristarán <jazzido@jazzido.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n/*****************************************************************************/\ntabula-extractor -> pdfbox\n\nThis product includes software (target/pdfbox-app-1.8.0.jar) developed at\nThe Apache Software Foundation (http://www.apache.org/). Licensed under the\nApache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0).\n\n/*****************************************************************************/\ntabula-extractor -> ext/lsd.c\n\n  LSD - Line Segment Detector on digital images\n\n  This code is part of the following publication and was subject\n  to peer review:\n\n    \"LSD: a Line Segment Detector\" by Rafael Grompone von Gioi,\n    Jeremie Jakubowicz, Jean-Michel Morel, and Gregory Randall,\n    Image Processing On Line, 2012. DOI:10.5201/ipol.2012.gjmr-lsd\n    http://dx.doi.org/10.5201/ipol.2012.gjmr-lsd\n\n  Copyright (c) 2007-2011 rafael grompone von gioi <grompone@gmail.com>\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as\n  published by the Free Software Foundation, either version 3 of the\n  License, or (at your option) any later version.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n  Additional permission under GNU GPL version 3 section 7\n\n  If you modify this Program, or any covered work, by linking or\n  combining it with Tabula (or a modified version of that library),\n  containing parts covered by the terms of \"MIT License\", the\n  licensors of this Program grant you additional permission to convey\n  the resulting work. Corresponding Source for a non-source form of\n  such a combination shall include the source code for the parts of\n  Tabula used as well as that of the covered work.\n"
  },
  {
    "path": "build/dist-README.txt",
    "content": "# Tabula\n\nTabula helps you liberate data tables trapped inside PDF files.\n\n* The latest downloads and documentation are always available at:\n  http://tabula.technology/\n\n* Read more about Tabula on OpenNews Source:\n  https://source.opennews.org/en-US/articles/introducing-tabula/\n\n* See the GitHub project for source code, technical info, and more:\n  https://github.com/tabulapdf/tabula\n\n* Find a bug? Report it on GitHub:\n  https://github.com/tabulapdf/tabula/issues\n\n© 2012-2020 Manuel Aristarán. Available under MIT License.\nSee `AUTHORS.txt` and `LICENSE.txt`.\n\n---\n\n## Using Tabula\n\nFirst, make sure you have a recent copy of Java installed. You can\ndownload Java at https://www.java.com/download/ . Tabula requires\na Java Runtime Environment compatible with Java 6 or Java 7.\n\n### Windows (tabula-win.zip)\n\nOpen tabula.exe and a browser should automatically open to\nhttp://127.0.0.1:8080/ . If not, open your web browser of choice and visit\nthat URL.\n\n### Mac OS X (tabula-mac.zip)\n\nOpen the Tabula app and a browser should automatically open to\nhttp://127.0.0.1:8080/ . If not, open your web browser of choice and visit\nthat URL.\n\n### JAR file for Linux/Other (tabula-jar.zip)\n\nOpen a terminal window, and `cd` to inside this `tabula` directory,\nthen run the following command\n\n  java -Dfile.encoding=utf-8 -Xms256M -Xmx1024M -jar tabula.jar\n\nThen, manually open your web browser to http://127.0.0.1:8080/ to access\nthe Tabula interface. Tabula binds to port 8080 by default. You can change\nit with the `warbler.port` option; for example, if you want to use port 9999:\n\n  java -Dfile.encoding=utf-8 -Xms256M -Xmx1024M -Dwarbler.port=9999 -jar tabula.jar\n\n(You can enable the old \"automatically open browser\" behavior by using\nthe `-Dtabula.openBrowser=true` option.)\n"
  },
  {
    "path": "build.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project name=\"tabula\" default=\"build\" basedir=\".\">\n\n  <property file=\"build.properties\"/>\n  <property name=\"build.dir\" value=\"build\"/>\n  <property name=\"mac.dir\" value=\"${build.dir}/mac\" />\n  <property name=\"windows.dir\" value=\"${build.dir}/windows\" />\n  <property name=\"full_version\" value=\"1.2.1.18052200\"/>\n  <property name=\"launch4j.dir\" location=\"${build.dir}/../launch4j\"  />\n  <property name=\"launch4j.bindir\" location=\"${build.dir}/../launch4j/bin\" />\n\n  <target name=\"check-jar-exists\">\n    <available file=\"${build.dir}/tabula.jar\" property=\"jar.exists\"/>\n  </target>\n\n  <target name=\"macbundle\" depends=\"check-jar-exists\" if=\"jar.exists\">\n    <mkdir dir=\"${mac.dir}\"/>\n\n    <!-- this must be a real JDK -->\n    <property name=\"java_home\" value=\"/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home\"/>\n\n    <taskdef\n        name=\"bundleapp\"\n        classname=\"com.oracle.appbundler.AppBundlerTask\"\n        classpath=\"${build.dir}/appbundler-1.0.jar\"\n        />\n\n    <bundleapp\n        outputdirectory=\"${build.dir}/mac\"\n        name=\"Tabula\"\n        displayname=\"Tabula\"\n        identifier=\"org.nerdpower.tabula.Tabula\"\n        icon=\"${build.dir}/icons/tabula.icns\"\n        shortversion=\"${full_version}\"\n        mainclassname=\"WarMain\"\n      >\n        <runtime dir=\"${java_home}\" />\n        <classpath file=\"${build.dir}/tabula.jar\" />\n        <option value=\"-Dapple.laf.useScreenMenuBar=true\"/>\n        <option value=\"-Dwarbler.port=8080\"/>\n        <option value=\"-Dtabula.openBrowser=true\"/>\n    </bundleapp>\n    <!--\n    To allow OSX to use this, you'll need to code sign.\n    Generate a self-signed \"Code Signing\" certificate[1], then enter\n    it in the -s option here and edit below section. Users can then\n    right-click or Control-click the app and \"Open\" and then tell OS X to\n    open anyway[2].\n      [1]: http://support.apple.com/kb/PH7173\n      [2]: http://support.apple.com/kb/HT5290\n\n    For production builds, you can get rid of \"Unidentified Developer\"\n    warnings by having a Mac Developer Account and a cert from[3]. Then\n    change -s option to something like 'Developer ID Application: Mike Tigas (68QUP6KP2C)',\n    based on your Developer Account & cert.\n      [3]: https://developer.apple.com/account/mac/certificate/certificateList.action\n    -->\n    <exec executable=\"codesign\" os=\"Mac OS X\">\n      <arg line=\"-f -s 'Developer ID Application: Mike Tigas (68QUP6KP2C)' --deep ${build.dir}/mac/Tabula.app\" />\n      <!-- <arg line=\"-f -s 'Tabula' ${build.dir}/mac/Tabula.app\" /> -->\n    </exec>\n  </target>\n\n  <target name=\"windows\" depends=\"check-jar-exists\" if=\"jar.exists\">\n    <mkdir dir=\"${windows.dir}\"/>\n    <taskdef\n        name=\"launch4j\"\n        classname=\"net.sf.launch4j.ant.Launch4jTask\"\n        classpath=\"${launch4j.dir}/launch4j.jar:${launch4j.dir}/lib/xstream.jar\"\n        />\n    <launch4j bindir=\"${launch4j.bindir}\">\n      <config\n          headerType=\"console\"\n          outfile=\"${windows.dir}/tabula.exe\"\n          jarPath=\"tabula.jar\"\n          dontWrapJar=\"true\"\n          icon=\"${build.dir}/icons/tabula.ico\">\n        <classPath mainClass=\"WarMain\">\n          <cp>tabula.jar</cp>\n        </classPath>\n        <jre minVersion=\"1.6.0\" jdkPreference=\"preferJre\" initialHeapSize=\"256\" maxHeapSize=\"1024\">\n          <opt>-Dfile.encoding=utf-8</opt>\n          <opt>-Dwarbler.port=8080</opt>\n          <opt>-Dtabula.openBrowser=true</opt>\n        </jre>\n        <versionInfo\n            fileVersion=\"${full_version}\"\n            txtFileVersion=\"${full_version}\"\n            fileDescription=\"tabula\"\n            copyright=\"© 2012-2020 Manuel Aristarán\"\n            productVersion=\"${full_version}\"\n            txtProductVersion=\"${full_version}\"\n            productName=\"Tabula\"\n            companyName=\"Tabula Team\"\n            internalName=\"tabula\"\n            originalFilename=\"tabula.exe\"\n            />\n      </config>\n    </launch4j>\n  </target>\n</project>\n"
  },
  {
    "path": "config.rb",
    "content": "require 'compass/import-once/activate'\n# Require any additional compass plugins here.\nrequire 'bootstrap-sass'\n# Set this to the root of your project when deployed:\nhttp_path = \"webapp/\"\ncss_dir = \"webapp/static/css\"\nsass_dir = \"webapp/static/sass\"\nimages_dir = \"webapp/static/img\"\njavascripts_dir = \"webapp/static/js\"\n\n# You can select your preferred output style here (can be overridden via the command line):\n# output_style = :expanded or :nested or :compact or :compressed\n\n# To enable relative paths to assets via compass helper functions. Uncomment:\n# relative_assets = true\n\n# To disable debugging comments that display the original location of your selectors. Uncomment:\nline_comments = false\n\n\n# If you prefer the indented syntax, you might want to regenerate this\n# project again passing --syntax sass, or you can uncomment this:\n# preferred_syntax = :sass\n# and then run:\n# sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass\n"
  },
  {
    "path": "config.ru",
    "content": "# encoding: UTF-8\nrequire 'rubygems'\nrequire 'bundler'\nBundler.require\n\n# Disable LittleCMS when running in JVM >= 1.8\n# https://pdfbox.apache.org/2.0/getting-started.html\njvmajor, jvminor = java.lang.System.getProperty('java.specification.version').split('.')\nif !jvminor.nil? && jvminor.to_i >= 8\n  java.lang.System.setProperty(\"sun.java2d.cmm\", \"sun.java2d.cmm.kcms.KcmsServiceProvider\")\nend\n\nrequire_relative './webapp/tabula_settings.rb'\nrequire_relative './webapp/tabula_web.rb'\n\npotential_root_uri_without_slashes = (defined?($servlet_context) ? $servlet_context.getContextPath : ENV[\"ROOT_URI\"])\n\nif potential_root_uri_without_slashes.nil? || potential_root_uri_without_slashes == ''\n  ROOT_URI = '/'\nelse\n  ROOT_URI = (potential_root_uri_without_slashes[0] == \"/\" ? '' : '/') + potential_root_uri_without_slashes +  (potential_root_uri_without_slashes[-1] == \"/\" ? '' : '/')\nend\n\nputs \"running under #{ROOT_URI} as root URI\" \n\n\nmap ROOT_URI do \n  run Cuba\nend\n\nif \"#{$PROGRAM_NAME}\".include?(\"tabula.jar\")\n  # only do this if running as jar or app. (if \"rackup\", we don't\n  # actually use 8080 by default.)\n\n  require 'java'\n\n  # don't do \"java_import java.net.URI\" -- it conflicts with Ruby URI and\n  # makes Cuba/Rack really really upset. just call \"java.*\" classes\n  # directly.\n  port = java.lang.Integer.getInteger('warbler.port', 8080)\n  url = \"http://127.0.0.1:#{port}\"\n\n  puts \"============================================================\"\n  puts url\n  puts \"============================================================\"\n\n  # Open browser after slight delay. (The server may take a while to actually\n  # serve HTTP, so we are trying to avoid a \"Could Not Connect To Server\".)\n  uri = java.net.URI.new(url)\n  sleep 0.5\n\n  puts \"should we open browser?\"\n  puts \"java.lang.Boolean.getBoolean('tabula.openBrowser'): #{java.lang.Boolean.getBoolean('tabula.openBrowser')}\"\n  have_desktop = false\n  if java.lang.Boolean.getBoolean('tabula.openBrowser')\n    puts \"java.awt.Desktop.isDesktopSupported: #{java.awt.Desktop.isDesktopSupported}\"\n    if java.awt.Desktop.isDesktopSupported\n      begin\n        desktop = java.awt.Desktop.getDesktop()\n      rescue\n        puts \"java.awt.Desktop.getDesktop(): no\"\n        desktop = nil\n      else\n        puts \"java.awt.Desktop.getDesktop(): yes\"\n        have_desktop = true\n      end\n    end\n  end\n\n  # if running as a jar or app, automatically open the user's web browser if\n  # the system supports it.\n  if have_desktop\n    puts \"\\n======================================================\"\n    puts \"Launching web browser to #{url}\\n\\n\"\n\n    begin\n      desktop.browse(uri)\n    rescue\n      puts \"Unable to launch your web browser, you will have to\"\n      puts \"manually open it to the above URL.\"\n    else\n      puts \"If it does not open in 10 seconds, you may manually open\"\n      puts \"a web browser to the above URL.\"\n    end\n\n    puts \"When you're done using the Tabula interface, you may\"\n    puts \"return to this window and press \\\"Control-C\\\" to close it.\"\n    puts \"======================================================\\n\\n\"\n  else\n    puts \"\\n======================================================\"\n    puts \"Server now listening at: #{url}\\n\\n\"\n    puts \"You may now open a web browser to the above URL.\"\n    puts \"When you're done using the Tabula interface, you may\"\n    puts \"return to this window and press \\\"Control-C\\\" to close it.\"\n    puts \"======================================================\\n\\n\"\n  end\nend\n"
  },
  {
    "path": "docker-compose.yml",
    "content": "version: '3.3'\nservices:\n  web: &web\n    build:\n      context: .\n    command: \"jruby -G -r jbundler -S rackup -p 9292 -o 0.0.0.0 config.ru\"\n    volumes:\n      - .:/app\n      - bundle:/usr/local/bundle\n    ports:\n      - 9292:9292\n\nvolumes:\n  bundle:\n"
  },
  {
    "path": "lib/tabula_java_wrapper.rb",
    "content": "java_import org.apache.pdfbox.pdmodel.PDDocument\njava_import org.apache.pdfbox.pdmodel.encryption.StandardDecryptionMaterial\n\nclass Java::TechnologyTabula::Table\n  attr_accessor :spec_index\n  def to_csv\n    sb = java.lang.StringBuilder.new\n    Java::TechnologyTabulaWriters.CSVWriter.new.write(sb, self)\n    sb.toString\n  end\n\n  def to_tsv\n    sb = java.lang.StringBuilder.new\n    Java::TechnologyTabulaWriters.TSVWriter.new.write(sb, self)\n    sb.toString\n  end\n\n  def to_json(*a)\n    sb = java.lang.StringBuilder.new\n    Java::TechnologyTabulaWriters.JSONWriter.new.write(sb, self)\n    sb.toString\n  end\nend\n\nmodule Tabula\n\n  def Tabula.extract_tables(pdf_path, specs, options={})\n    options = {\n      :password => '',\n      :detect_ruling_lines => true,\n      :vertical_rulings => [],\n      :extraction_method => \"guess\",\n    }.merge(options)\n\n    specs.each_with_index{|spec, i| spec[\"spec_index\"] = i }\n    specs = specs.group_by { |s| s['page'] }\n    pages = specs.keys.sort\n\n    extractor = Extraction::ObjectExtractor.new(pdf_path,\n                                                options[:password])\n\n    sea = Java::TechnologyTabulaExtractors.SpreadsheetExtractionAlgorithm.new\n    bea = Java::TechnologyTabulaExtractors.BasicExtractionAlgorithm.new\n\n    Enumerator.new do |y|\n      extractor.extract(pages.map { |p| p.to_java(:int) }).each do |page|\n        specs[page.getPageNumber].each do |spec|\n          if [\"spreadsheet\", \"original\", \"basic\", \"stream\", \"lattice\"].include?(spec['extraction_method'])\n            use_spreadsheet_extraction_method = (spec['extraction_method'] == \"spreadsheet\" || spec['extraction_method'] == \"lattice\"  )\n          else # guess\n            use_spreadsheet_extraction_method = sea.isTabular(page)\n          end\n\n          area = page.getArea(spec['y1'], spec['x1'], spec['y2'], spec['x2'])\n\n          table_extractor = use_spreadsheet_extraction_method ? sea : bea\n          table_extractor.extract(area).each { |table| table.spec_index = spec[\"spec_index\"]; y.yield table }\n        end\n      end;\n      extractor.close!\n    end\n\n  end\n\n\n  module Extraction\n\n    def Extraction.openPDF(pdf_filename, password='')\n      raise Errno::ENOENT unless File.exists?(pdf_filename)\n      PDDocument.load(java.io.File.new(pdf_filename))\n    end\n\n    class ObjectExtractor < Java::TechnologyTabula.ObjectExtractor\n\n      alias_method :close!, :close\n\n      # TODO: the +pages+ constructor argument does not make sense\n      # now that we have +extract_page+ and +extract_pages+\n      def initialize(pdf_filename, pages=[1], password='', options={})\n        raise Errno::ENOENT unless File.exists?(pdf_filename)\n        @pdf_filename = pdf_filename\n        @document = Extraction.openPDF(pdf_filename, password)\n\n        super(@document)\n      end\n\n      def page_count\n        @document.get_number_of_pages\n      end\n\n    end\n\n    class PagesInfoExtractor < ObjectExtractor\n\n      def pages\n        Enumerator.new do |y|\n          self.extract.each do |page|\n            y.yield({\n                      :width => page.getWidth,\n                      :height => page.getHeight,\n                      :number => page.getPageNumber,\n                      :rotation => page.getRotation.to_i,\n                      :hasText => page.hasText\n                    })\n            end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/tabula_job_executor/executor.rb",
    "content": "require 'java'\njava_import java.util.concurrent.ThreadPoolExecutor\njava_import java.util.concurrent.TimeUnit\njava_import java.util.concurrent.LinkedBlockingQueue\n\nrequire 'jruby/synchronized'\n\nrequire 'securerandom'\nrequire 'singleton'\n\nmodule Tabula\n  class NoTextDataException < IOError; end\n\n  module Background\n\n    class JobExecutor < java.util.concurrent.ThreadPoolExecutor\n      include Singleton\n\n      attr_reader :jobs, :futures_jobs\n\n      def initialize\n        @jobs = Hash.new.extend(JRuby::Synchronized)\n        @futures_jobs = Hash.new.extend(JRuby::Synchronized)\n\n        super(3, # core pool size\n              5, # max pool size\n              300, # keep idle threads 5 minutes\n              TimeUnit::SECONDS,\n              LinkedBlockingQueue.new)\n\n        at_exit do\n          self.shutdown\n          self.shutdownNow\n        end\n      end\n\n      def afterExecute(runnable, throwable)\n        super(runnable, throwable)\n        if throwable.nil? and runnable.instance_of?(Java::JavaUtilConcurrent::FutureTask)\n          begin\n            if runnable.isDone\n              runnable.get # 'get' the Future, so it rethrows exceptions if any\n            end\n          rescue Java::JavaUtilConcurrent::ExecutionException => e\n            throwable = e\n          rescue Java::JavaUtilConcurrent::CancellationException => e\n            throwable = e.getCause\n          rescue Java::JavaLang::InterruptedException => e\n            Java::JavaLang::Thread.currentThread.interrupt\n          end\n          if throwable.nil?\n            # task finished OK\n            @futures_jobs[runnable].completed\n          else\n            throwable.printStackTrace(java.lang.System.out)\n            # finished with exception\n            throwable.printStackTrace # XXX TODO better exception logging\n            @futures_jobs[runnable].failed(throwable.toString)\n          end\n        end\n      end\n\n      def submit(job)\n        @jobs[job.uuid] = job\n        future = super(job)\n        @futures_jobs[future] = job\n      end\n\n      class << self\n        def get(uuid)\n          instance.jobs[uuid]\n        end\n\n        def get_by_batch(uuid)\n          instance.jobs.select { |k, j|\n            j.options[:batch] == uuid\n          }\n        end\n      end\n    end\n\n    class Job\n      include java.util.concurrent.Callable\n\n      attr_accessor :options, :status\n      attr_reader :uuid\n\n      def initialize(options={})\n        @uuid = SecureRandom.uuid\n        @status = {'num' => 0 }\n        self.options = options\n      end\n\n      def [](k)\n        self.options[k]\n      end\n\n      def name\n        \"#{self.class.name}(#{options.inspect unless options.empty?})\"\n      end\n\n      def call\n        self.status.merge!({ 'status' => 'working', 'started_on' => Time.now })\n        perform\n        @uuid\n      end\n\n      def [](k)\n        options[k]\n      end\n\n      def at(num, total, *messages)\n        self.status.merge!({ 'status' => 'working', 'num' => num, 'total' => total, 'messages' => messages })\n      end\n\n      def queued\n        self.status.merge!({ 'status' => 'queued', 'queued_on' => Time.now })\n      end\n\n      def warn(*warnings)\n        self.status.merge!({ 'warnings' => warnings })\n      end\n\n      def failed(*messages)\n        self.status.merge!({ 'status' => 'failed', 'messages' => messages})\n      end\n\n      def completed\n        self.status.merge!({ 'status' => 'completed', 'completed_on' => Time.now })\n      end\n\n      def pct_complete\n        case status['status']\n          when 'completed' then 100\n          when 'queued' then 0\n          else\n          t = (status['total'] == 0 || status['total'].nil?) ? 1 : status['total']\n          (((status['num'] || 0).to_f / t.to_f) * 100).to_i\n        end\n      end\n\n      def message\n        self.status['messages']\n      end\n\n      alias_method :message?, :message\n\n      def warning\n        self.status['warnings']\n      end\n\n      alias_method :warning?, :warning\n\n      STATUSES = %w{queued working completed failed killed}.freeze\n      STATUSES.each do |status|\n        define_method(\"#{status}?\") do\n          self.status['status'] === status\n        end\n      end\n\n      class << self\n        def create(options)\n          job = self.new(options)\n          JobExecutor.instance.submit(job)\n          job.uuid\n        end\n      end\n\n    end\n  end\nend\n\n\nif __FILE__ == $0\n\n  class K < Tabula::Background::Job\n    def perform\n      options[:start].upto(options[:end]) do |i|\n        puts \"I'm #{@uuid}: #{i}/#{options[:end]}\"\n        at(i, options[:end])\n        sleep 1\n      end\n      @uuid\n    end\n  end\n\n  class J < Tabula::Background::Job\n    def perform\n      options[:start].upto(options[:end]) do |i|\n        puts \"I'm #{@uuid}: #{i}/#{options[:end]}\"\n        at(i, options[:end])\n        raise 'caca'\n        sleep 1\n      end\n    end\n  end\n\n  j1 = K.create(:start => 1, :end => 20)\n  j2 = K.create(:start => 25, :end => 40)\n  j3 = J.create(:start => 1, :end => 6)\n\n  Thread.new do\n    loop {\n      puts \"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"\n\n      # puts \"STATUS OF J1 IN EXECUTOR: #{Tabula::Background::JobExecutor.get(j1)}\"\n      # puts \"STATUS OF J2 IN EXECUTOR: #{Tabula::Background::JobExecutor.get(j2)}\"\n      # puts \"STATUS OF J3 IN EXECUTOR: #{Tabula::Background::JobExecutor.get(j3)}\"\n      puts Tabula::Background::JobExecutor.instance.futures_jobs.inspect\n      sleep 1\n    }\n  end\nend\n"
  },
  {
    "path": "lib/tabula_job_executor/jobs/detect_tables.rb",
    "content": "require 'java'\n\nrequire_relative '../executor.rb'\n\nclass DetectTablesJob < Tabula::Background::Job\n  include Observable\n  def perform\n    filepath = options[:filepath]\n    document_id = options[:id]\n\n    page_areas_by_page = []\n\n    begin\n      extractor = Tabula::Extraction::ObjectExtractor.new(filepath, :all)\n      page_count = extractor.page_count\n      nda = Java::TechnologyTabulaDetectors::NurminenDetectionAlgorithm.new\n      extractor.extract.each do |page|\n        page_index = page.getPageNumber\n\n        at( (page_count + page_index) / 2, page_count, \"auto-detecting tables...\") #starting at 50%...\n        changed\n\n        areas = nda.detect(page)\n        page_areas_by_page << areas.map { |rect|\n          [ rect.getLeft,\n            rect.getTop,\n            rect.getWidth,\n            rect.getHeight ]\n        }\n      end\n\n    rescue Java::JavaLang::Exception => e\n      warn(\"Table auto-detect failed. You may need to select tables manually.\")\n    ensure\n      extractor.close!\n    end\n\n    Tabula::Workspace.instance.add_file(page_areas_by_page.to_json, document_id, 'tables.json')\n\n    at(100, 100, \"complete\")\n    return nil\n  end\nend\n"
  },
  {
    "path": "lib/tabula_job_executor/jobs/generate_document_data.rb",
    "content": "require 'json'\nrequire 'jruby/synchronized'\n\nrequire_relative '../executor.rb'\n\nclass GenerateDocumentDataJob < Tabula::Background::Job\n  include JRuby::Synchronized\n\n  # args: (:filename, :id)\n  def perform\n\n    filepath = options[:filepath]\n    original_filename = options[:original_filename]\n    id = options[:id]\n\n    # return some status to browser\n    at(1, 100, \"opening workspace...\")\n\n    doc = { 'original_filename' => original_filename,\n            'id' => id,\n            'time' => Time.now.to_i,\n            'page_count' => '?',\n            'size' => File.size(filepath),\n            'thumbnail_sizes' => options[:thumbnail_sizes]\n          }\n    at(5, 100, \"analyzing PDF text...\")\n\n    extractor = Tabula::Extraction::PagesInfoExtractor.new(filepath)\n    page_data = extractor.pages.to_a\n    doc['page_count'] = page_data.size\n    unless page_data.any? { |pd| pd[:hasText] }\n      at(0, 100, \"No text data found\")\n      raise Tabula::NoTextDataException, \"no text data found\"\n    end\n\n    Tabula::Workspace.instance.add_document(doc, page_data)\n    at(100, 100, \"complete\")\n    extractor.close!\n    return nil\n  end\nend\n"
  },
  {
    "path": "lib/tabula_job_executor/jobs/generate_thumbnails.rb",
    "content": "require_relative '../executor.rb'\nrequire_relative '../../thumbnail_generator.rb'\n\nclass GenerateThumbnailJob < Tabula::Background::Job\n  # args: (:file, :output_dir, :thumbnail_sizes, :page_index_job_uuid)\n\n  def perform\n\n    file_id = options[:file_id]\n    upload_id = self.uuid\n    filepath = options[:filepath]\n    output_dir = options[:output_dir]\n    thumbnail_sizes = options[:thumbnail_sizes]\n\n    generator = PDFBoxThumbnailGenerator.new(filepath, output_dir, file_id, thumbnail_sizes)\n    generator.add_observer(self, :at)\n    generator.generate_thumbnails!\n\n  end\nend\n"
  },
  {
    "path": "lib/tabula_workspace.rb",
    "content": "require 'jruby/synchronized'\nrequire 'singleton'\n\nmodule Tabula\n  class Workspace\n    include JRuby::Synchronized\n    include Singleton\n\n    STARTING_VALUE = {\"pdfs\" => [], \"templates\" => [], \"version\" => 2}\n\n\n    def initialize(data_dir=TabulaSettings.getDataDir)\n      unless File.directory?(data_dir)\n        raise \"DOCUMENTS_BASEPATH does not exist or is not a directory.\"\n      end\n\n      @data_dir = data_dir\n      @workspace_path = File.join(@data_dir, \"pdfs\", \"workspace.json\")\n      @workspace = STARTING_VALUE\n      if !File.exists?(@workspace_path)\n        FileUtils.mkdir_p(File.join(@data_dir, \"pdfs\"))\n      end\n    end\n\n    def add_document(document, pages)\n      read_workspace!\n      @workspace[\"pdfs\"].unshift(document)\n      add_file(pages.to_json, document['id'], 'pages.json')\n      flush_workspace!\n    end\n\n    def delete_document(document_id)\n      read_workspace!\n      @workspace[\"pdfs\"].delete_if { |d| d['id'] == document_id }\n      flush_workspace!\n\n      FileUtils.rm_rf(get_document_dir(document_id))\n    end\n\n    def delete_page(document_id, page_number)\n      # TODO\n      raise \"Not Implemented\"\n    end\n\n    def get_document_metadata(document_id)\n      read_workspace!\n      @workspace[\"pdfs\"].find { |d| d['id'] == document_id }\n    end\n\n    def get_document_pages(document_id)\n      JSON.parse(File.join(get_document_dir(document_id), 'pages.json').read)\n    end\n\n    def get_document_path(document_id)\n      File.join(get_document_dir(document_id), 'document.pdf')\n    end\n\n    def list_documents\n      read_workspace!\n      @workspace[\"pdfs\"]\n    end\n\n\n\n    def get_data_dir()\n      @data_dir\n    end\n\n    def add_file(contents, document_id, filename)\n      p = get_document_dir(document_id)\n\n      File.open(File.join(p, filename), 'w') do |f|\n        f.write contents\n      end\n    end\n\n    def move_file(path, document_id, filename)\n      FileUtils.mv(path, File.join(get_document_dir(document_id), filename))\n    end\n\n\tdef copy_file(path, document_id, filename)\n\t   FileUtils.cp_r(path, File.join(get_document_dir(document_id), filename))\n\tend\n\n    def list_templates\n      read_workspace!\n      @workspace[\"templates\"]\n    end\n\n    def get_template_metadata(template_id)\n      read_workspace!\n      @workspace[\"templates\"].find { |d| d['id'] == template_id }\n    end\n    def get_template_body(template_id)\n      puts File.join(get_templates_dir, \"#{template_id}.tabula-template.json\")\n      open(File.join(get_templates_dir, \"#{template_id}.tabula-template.json\"), 'r'){|f| f.read }\n    end\n\n    def add_template(template_metadata)\n      read_workspace!\n\n      # write template metadata to workspace\n      @workspace[\"templates\"].insert(0,{\n                                      \"name\" => template_metadata[\"name\"].gsub(\".tabula-template.json\", \"\"), \n                                      \"selection_count\" => template_metadata[\"selection_count\"],\n                                      \"page_count\" => template_metadata[\"page_count\"], \n                                      \"time\" => template_metadata[\"time\"], \n                                      \"id\" => template_metadata[\"id\"]\n                                    })\n      # write template file to disk\n      write_template_file(template_metadata)\n      flush_workspace!\n    end\n\n    def replace_template_metadata(template_id, template_metadata)\n      read_workspace!\n      idx = @workspace[\"templates\"].index{|t| t[\"id\"] == template_id}\n      @workspace[\"templates\"][idx] = template_metadata.select{|k,_| [\"name\", \"selection_count\", \"page_count\", \"time\", \"id\"].include?(k) }\n      flush_workspace!\n    end\n\n\n\n    def delete_template(template_id)\n      read_workspace!\n      @workspace[\"templates\"].delete_if { |t| t['id'] == template_id }\n      flush_workspace!\n      File.delete(File.join(get_templates_dir, \"#{template_id}.tabula-template.json\"))\n    end\n\n\n    private\n\n    def write_template_file(template_metadata)\n      template_name = template_metadata[\"name\"]\n      template_id = Digest::SHA1.hexdigest(Time.now.to_s + template_name) # just SHA1 of time isn't unique with multiple uploads\n      template_filename = template_id + \".tabula-template.json\"\n      open(File.join(get_templates_dir, template_filename), 'w'){|f| f << JSON.dump(template_metadata[\"template\"])}\n    end\n\n    def get_templates_dir\n      p = File.join(@data_dir, 'templates')\n      if !File.directory?(p)\n        FileUtils.mkdir_p(p)\n      end\n      p\n    end\n    def get_document_dir(document_id)\n      p = File.join(@data_dir, 'pdfs', document_id)\n      if !File.directory?(p)\n        FileUtils.mkdir_p(p)\n      end\n      p\n    end\n\n\n    def read_workspace!\n      return STARTING_VALUE unless File.exists?(@workspace_path)\n      File.open(@workspace_path) do |f|\n        @workspace = JSON.parse(f.read)\n      end\n      # what if the already-existing workspace is v1? i.e. if it's just an array?\n      # then we'll make it the new kind, seamlessly.\n      if @workspace.is_a? Array\n        @workspace = {\"pdfs\" => @workspace, \"templates\" => [], \"version\" => 2}\n        flush_workspace!\n      end\n      @workspace\n    end\n\n    def flush_workspace!\n      File.open(@workspace_path, 'w') do |f|\n        f.write @workspace.to_json\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/thumbnail_generator.rb",
    "content": "# coding: utf-8\nrequire 'java'\nrequire 'observer'\n\njava_import javax.imageio.ImageIO\njava_import java.awt.image.BufferedImage\njava_import java.awt.Image\njava_import java.io.ByteArrayOutputStream\n\njava_import org.apache.pdfbox.pdmodel.PDDocument\njava_import org.apache.pdfbox.rendering.PDFRenderer\n\nclass AbstractThumbnailGenerator\n  include Observable\n\n  def initialize(pdf_filename, output_directory, sizes=[2048, 560])\n    raise Errno::ENOENT unless File.directory?(output_directory)\n    raise ArgumentError if sizes.empty?\n    @sizes = sizes.sort.reverse\n    @output_directory = output_directory\n    @pdf_filename = pdf_filename\n  end\n\n  def generate_thumbnails!\n    raise 'NotImplemented'\n  end\nend\n\nclass PDFBoxThumbnailGenerator < AbstractThumbnailGenerator\n  def initialize(pdf_filename, output_directory, document_id, sizes=[2048, 560])\n    super(pdf_filename, output_directory, sizes)\n    @sizes = sizes\n    @pdf_document = PDDocument.load(java.io.File.new(pdf_filename))\n    @document_id = document_id\n  end\n\n  def generate_thumbnails!\n    total_pages = @pdf_document.getNumberOfPages\n    renderer = PDFRenderer.new(@pdf_document)\n\n    total_pages.times do |pi|\n      image = renderer.renderImageWithDPI(pi, 75)\n      imageWidth = image.getWidth.to_f\n      imageHeight = image.getHeight.to_f\n\n      @sizes.each do |size|\n        scale = size / imageWidth\n        bi = BufferedImage.new(size, (imageHeight * scale).round, image.getType)\n        bi.getGraphics.drawImage(image.getScaledInstance(size, (imageHeight * scale).round, Image::SCALE_SMOOTH), 0, 0, nil)\n\n        sio = StringIO.new\n        out = sio.to_outputstream\n        ImageIO.write(bi, 'png', out)\n        Tabula::Workspace.instance.add_file(sio.string, @document_id, \"document_#{size}_#{pi+1}.png\")\n      end\n\n      changed\n      notify_observers(pi+1, total_pages, \"generating page thumbnails…\")\n    end\n    @pdf_document.close\n  end\nend\n\n##\n# use /usr/bin/mudraw for faster thumbnail generation\n# useful for hosted instances of Tabula\nclass MUDrawThumbnailGenerator < AbstractThumbnailGenerator\n\n  def initialize(pdf_filename, output_directory, sizes=[2048, 560], mudraw='/usr/local/bin/mudraw')\n    super(pdf_filename, output_directory, sizes)\n    @mudraw = mudraw\n  end\n\n  def generate_thumbnails!\n    @sizes.each_with_index do |size, i|\n      out = File.join(@output_directory, \"document_#{size}_%d.png\")\n\n      `#{@mudraw} -o \"#{out}\" -w #{size} \"#{@pdf_filename}\"`\n      changed\n      notify_observers(i+1, @sizes.length, \"generating page thumbnails...\")\n    end\n  end\nend\n"
  },
  {
    "path": "webapp/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<!-- Tabula.api_version : ask for it on the console. -->\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <meta name=\"description\" content=\"\">\n    <meta name=\"author\" content=\"\">\n    <link rel=\"shortcut icon\" href=\"img/favicon.ico\" type=\"image/x-icon\">\n    <link rel=\"icon\" href=\"img/favicon.ico\" type=\"image/x-icon\">\n\n    <title>Tabula</title>\n\n    <base href=\"/\"><!-- overwritten dynamically with the value of $servlet_context.getContextPath or ENV[\"ROOT_URI\"] -->\n\n    <link href=\"css/styles.css\" rel=\"stylesheet\">\n\n    <!-- Selector-specific CSS -->\n    <link href=\"css/selectors.css\" rel=\"stylesheet\">\n\n    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->\n    <!--[if lt IE 9]>\n      <script src=\"https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js\"></script>\n      <script src=\"https://oss.maxcdn.com/respond/1.4.2/respond.min.js\"></script>\n    <![endif]-->\n\n    <script type=\"text/javascript\" src=\"js/vendor/jquery.min.js\"></script>\n    <script type=\"text/javascript\" src=\"js/vendor/underscore-min.js\"></script>\n    <script type=\"text/javascript\" src=\"js/vendor/backbone-min.js\"></script>\n    <script type=\"text/javascript\" src=\"js/vendor/bootstrap.js\"></script>\n  </head>\n\n\n  <body data-spy=\"scroll\" data-target=\".nav.sidebar-nav\" data-offset=\"0\">\n    <div class=\"ribbon-wrapper-green\" id=\"dev-mode-ribbon\" style=\"display: none;\"><div class=\"ribbon-green\">DEV mode</div></div>\n\n    <!-- Fixed navbar -->\n    <nav class=\"navbar navbar-default navbar-fixed-top\" role=\"navigation\">\n      <div class=\"container\">\n        <div class=\"navbar-header\">\n          <a class=\"navbar-brand\" href=\"\">Tabula</a>\n        </div>\n        <div id=\"navbar\" class=\"navbar-collapse collapse\">\n          <ul class=\"nav navbar-nav navbar-left\">\n            <li><a id=\"upload-nav\" href=\"\">My Files</a></li>\n            <li><a id=\"templates-nav\" href=\"mytemplates\">My Templates</a></li>\n            <li><a id=\"about-nav\" href=\"about\">About</a></li>\n            <li><a id=\"help-nav\" href=\"help\">Help</a></li>\n            <li><a href=\"https://github.com/tabulapdf/tabula\" target=\"_blank\">Source Code</a></li>\n          </ul>\n          <ul class=\"nav navbar-nav navbar-right\">\n            <li><a target=\"_blank\" href=\"https://opencollective.com/tabulapdf\">Support Tabula on OpenCollective!</a></li>\n          </ul>\n        </div><!--/.nav-collapse -->\n      </div>\n    </nav>\n\n\n\n\n    <div id=\"tabula-app\"> <!-- TODO remember to change this ID to match what page we're on.  id=\"page-selections\", id=\"page-export\"-->\n    </div>\n    <div id=\"tabula-dataview\">\n\n    </div>\n\n    <div id=\"templates\">\n      <script type=\"text/template\" id=\"page-template\" >\n        <span class=\"page-number\"><%= number %>. </span>\n        <div class=\"page\" id=\"page-div-<%= number %>\">\n          <img onload=\"$(this).data('loaded', 'loaded');\" src=\"<%= image_url %>\" draggable=\"false\" unselectable=\"on\" > <!-- unselectable is for IE/Opera -->\n        </div>\n      </script>\n      <script type=\"text/template\" id=\"thumbnail-template\" >\n        <a href=\"#page-<%= number %>\"><img src=\"<%= image_url %>\"></a>\n        <div class=\"remove\">\n          <span class=\"glyphicon glyphicon-remove delete-page\"></span>\n          <!-- <span title=\"rotate this page right\" class=\"icon-repeat rotate-left\"></span>\n          <span title=\"rotate this page left\" class=\"icon-repeat flip rotate-right\"></span> -->\n        </div>\n        <p><%= number %></p>\n      </script>\n\n      <script type=\"text/template\" id=\"export-control-panel-template\">\n        <form id=\"download-form\" action=\"pdf/<%=pdf_id%>/data?format=csv\" method=\"post\">\n          <div id=\"hidden-fields\">\n            <input type='hidden' class='data-query' name='new_filename' value='<%=original_filename%>' >\n            <input type='hidden' class='data-query' name='coords' value='<%=list_of_coords%>' >\n          </div>\n          <!-- <input class=\"filename\" name=\"new_filename\" value=\"<%= new_filename || original_filename %>\"></input> -->\n          <span class=\"filename\"><%= original_filename %></span>\n          <label for=\"format\">Export Format:</label>\n          <select name=\"format\" <%=disableIfNoData%> class=\"form-control format\">\n            <option value=\"csv\">CSV</option>\n            <option value=\"tsv\">TSV</option>\n            <option value=\"bbox\">JSON (dimensions)</option>\n            <option value=\"json\">JSON (data)</option>\n            <!-- <option value=\"&#x1F4A9;SV\">&#x1F4A9;SV</option> -->\n            <option value=\"zip\">zip of CSVs</option>\n            <!-- <option value=\"xml\">XML</option> -->\n            <option value=\"script\">Script</option>\n          </select>\n          <button type=\"submit\" <%=disableIfNoData%> id=\"download-data\" class=\"btn btn-default\" data-action='pdf/<%=pdf_id%>/data'>\n            <span class=\"glyphicon glyphicon-refresh\"></span>\n            <span class=\"glyphicon glyphicon-download\"></span>\n            Export\n          </button>\n          <button type=\"button\" id=\"copy-csv-to-clipboard\" class=\"btn btn-default\" <%=disableIfNoData%> <%=copyDisabled%> >\n            <span class=\"glyphicon glyphicon-paperclip\"></span>\n            <span class=\"clipboard-text\">Copy to Clipboard</span>\n          </button>\n        </form>\n      </script>\n\n      <script type=\"text/template\" id=\"select-control-panel-template\" >\n        <span class=\"filename\"><%= original_filename %></span>\n        <div class=\"dropdown\" <%= disable_load_template %> style=\"display: inline;\">\n          <button type=\"button\" class=\"dropdown-toggle btn btn-info\" data-toggle=\"dropdown\" href=\"#\" ><span class=\"glyphicon glyphicon-import\" title=\"You may only load a template if there are no selections active in your PDF.\"></span>Templates</button>\n          <div id=\"template-dropdown-container\" class=\"dropdown-menu\">\n            <ul>\n              <li>\n                <a href=\"javascript:void(0)\"><button type=\"button\" id=\"save-template\" class=\"btn btn-link\" style=\"min-width: 155px;\" <%= disable_save_template %>> <span class=\"button-text\">Save Selections as Template</span> <span class=\"glyphicon glyphicon-export\"></span></button></a>\n              </li>\n            </ul>\n            <p style=\"margin-left:5px;\">Load templates:</p>\n            <div id=\"template-dropdown-templates-list-container\">\n            </div>\n          </div>\n        </div>\n\n\n        <a href=\"javascript:void(0)\"><button type=\"button\" id=\"clear-all-selections\" class=\"btn btn-default\" <%= disable_clear_all_selections %>><span class=\"glyphicon glyphicon-remove-circle\"></span> Clear All Selections</button></a>\n        <button id=\"restore-detected-tables\" type=\"button\" class=\"btn btn-default <%= restore_detected_tables %>\" <%= disabled_if_there_are_selections %>><span class=\"glyphicon glyphicon-flash\"></span><span class=\"glyphicon glyphicon-refresh\"></span> Autodetect Tables</button>\n\n\n\n        <span style=\"float: right\">\n          <a href=\"javascript:void(0)\"><button type=\"button\" id=\"all-data\" class=\"btn btn-success\" <%= disable_download_all %>><span class=\"glyphicon glyphicon-list-alt\"></span> Preview & Export Extracted Data</button></a>\n        </span>\n\n\n\n\n        <span style=\"clear: both;\">\n      </script>\n\n      <script type=\"text/template\" id=\"select-sidebar-template\">\n        <ul id=\"thumbnail-list\" class=\"thumbnail-list\">\n        </ul>\n      </script>\n\n      <script type=\"text/template\" id=\"export-page-sidebar-template\">\n          <h4>Is the extracted data incorrect?</h4>\n\n          <p>You can revise your selected cells or try an alternate extraction method.</p>\n\n          <h5>Revise Selected Cells</h5>\n          <p>Data has been extracted from the cells you selected in the previous step. You can revise your selection(s) to add or remove cells.</p>\n          <p>\n            <button type=\"button\" class=\"btn btn-default\" id=\"revise-selections\"><span class=\"glyphicon glyphicon-arrow-left\"></span> Revise selection(s)</button>\n          </p>\n\n          <h5>Choose Alternate Extraction Method</h5>\n\n          <p>The current preview uses the <strong>Stream</strong> extraction method. If the data is not mapped to the correct cells, try the <strong>Lattice</strong> method instead.</p>\n\n          <div class=\"btn-group\" data-toggle=\"buttons-radio\" id=\"extraction-method-btns\" <%=disableExtractionMethodButtons%> >\n            <button type=\"button\" id=\"original-method-btn\" class=\"btn btn-default extraction-method-btn\" data-method=\"original\" ><span class=\"glyphicon glyphicon-th stream\"></span> Stream</button>\n            <button type=\"button\" id=\"spreadsheet-method-btn\" class=\"btn btn-default extraction-method-btn\" data-method=\"spreadsheet\"><span class=\"glyphicon glyphicon-th lattice\"></span> Lattice</button>\n          </div>\n\n          <p>\n            Stream looks for <em>whitespace</em> between columns, while Lattice looks for <em>boundary lines</em> between columns.\n          </p>\n\n         <h5>Still look wrong?</h5>\n          <p><a href=\"http://www.github.com/tabulapdf/tabula/issues/new\">Contact the developers</a> and tell us what you tried to do that didn’t work.</p>\n      </script>\n\n      <!-- TODO: abstract out commonalities of select/export page templates -->\n      <script type=\"text/template\" id=\"export-page-template\">\n        <div id=\"sidebar\">\n        </div>\n\n        <div id=\"main-pane\">\n            <div id=\"control-panel\">\n            </div>\n\n           <h2>Preview of Extracted Tabular Data</h2>\n            <div id=\"table-container\">\n            <% if(data.length){ %>\n              <% _(data).each(function(table){ %>\n              <table class=\"table table-bordered extracted-data\">\n                <tbody>\n                <% _(table).each(function(row){ %>\n                  <tr>\n                    <% _(row).each(function(cell){ %>\n                      <td><%= cell %></td>\n                    <% }) %>\n                  </tr>\n                <% }) %>\n                </tbody>\n              </table>\n              <% }) %>\n            <% } else if (loading) { %>\n             <div class=\"alert alert-success\" id=\"loading\"><span id=\"spinner\"></span><span style=\"position: relative; left: 16px; font-size: 24px;\">Loading...</span></div>\n            <% } else if (error_message) { %>\n               <p><strong>Tabula</strong> couldn't finish processing your request. <!-- We'd appreciate if you could <a href=\"https://github.com/jazzido/tabula/issues/new\">report this error in our issue tracker</a>. If possible, please include a link to the document that caused the error and the text below: --></p>\n                 <pre class=\"error\"><%= error_message %></pre>\n            <% } else { %>\n              <span class=\"no-data\">No data.</span>\n            <% } %>\n            </div>\n        </div>\n      </script>\n\n      <script type=\"text/template\" id=\"pdf-view-template\" >\n        <div id=\"sidebar\">\n          <!-- thumbnails get rendered here by JS -->\n        </div>\n        <div id=\"main-pane\">\n          <div id=\"control-panel\">\n          </div>\n\n          <div id=\"pages-container\">\n          </div>\n        </div>\n        <nestedscript type=\"text/javascript\" src=\"js/vendor/spin.min.js\"></nestedscript>\n        <nestedscript type=\"text/javascript\" src=\"js/resizableSelection.js\"></nestedscript>\n        <nestedscript type=\"text/javascript\" src=\"js/rectangularSelector.js\"></nestedscript>\n        <nestedscript type=\"text/javascript\" src=\"js/vendor/ZeroClipboard.min.js\"></nestedscript>\n        <!-- <nestedscript type=\"text/javascript\" src=\"js/debug_pdf_view.js\"></nestedscript>  -->\n      </script>\n\n\n      <script type=\"text/template\" id=\"failed-uploads-template\">\n        <h4>Failed Uploads</h4>\n        <ol id=\"failed-uploads\">\n\n        </ol>\n      </script>\n      <script type=\"text/template\" id=\"failed-uploaded-file-template\">\n        <a href='/pdf/<%= id %>'><%= original_filename %></a>: <%= failure_message %>\n      </script>\n\n\n      <script type='text/template' id='file-upload-template'>\n        <h5><%= filename %></h5>\n        <span id=\"message\"><%= message %></span>\n        <ul class=\"list-unstyled\">\n          <% for(var warning in warnings) { %>\n              <li class=\"text-danger\">Warning: <%= warnings[warning] %></li>\n          <% } %>\n        </ul>\n        <div class=\"progress\">\n          <div class=\"progress-bar\" role=\"progressbar\" aria-valuenow=\"60\" aria-valuemin=\"0\" aria-valuemax=\"100\" style=\"width: <%= pct_complete %>%;\"><span class=\"sr-only\"> <%= pct_complete %>% Complete </span></div>\n        </div>\n      </script>\n\n      <script type=\"text/template\" id=\"progress-bars-template\">\n        <h4>Upload Progress</h4>\n        <div id=\"progress-bars-container\">\n\n        </div>\n      </script>\n\n      <script type=\"text/template\" id=\"new-version-template\">\n        <div class=\"alert alert-warning alert-dismissable\" id=\"update-alert\">\n        <button type=\"button\" class=\"close\" data-dismiss=\"alert\" aria-hidden=\"true\">&times;</button>\n        <strong>New version!</strong> <a href=\"<%= new_release.html_url %>\">Tabula <span id=\"new-version\"><%= new_release.name %></span></a> is available (you have <span id=\"installed-version\"><%= api_version %></span>)\n        </div>\n      </script>\n\n      <script type=\"text/template\" id=\"notification-template\">\n        <div class=\"alert alert-warning alert-dismissable\" id=\"custom-alert\">\n        <button type=\"button\" class=\"close\" data-dismiss=\"alert\" aria-hidden=\"true\">&times;</button>\n        <strong><%= notification.name %></strong> <span class=\"custom-alert-body\"><%= notification.body %></span>\n        </div>\n      </script>\n\n\n      <script type=\"text/template\" id=\"uploader-template\">\n        <div class=\"container\">\n          <div class=\"jumbotron\">\n\n            <div id=\"new-version-alert\"></div>\n            <div id=\"notification-alert\"></div>\n\n            <div id=\"upload-form-container\">\n              <h4>Import one or more PDFs</h4>\n              <form id=\"upload\" action=\"upload.json\" method=\"post\" enctype=\"multipart/form-data\" class=\"form-inline\">\n\n                <div class=\"input-group\">\n                  <!-- we are using this here: http://www.abeautifulsite.net/whipping-file-inputs-into-shape-with-bootstrap-3/ -->\n                  <span class=\"input-group-btn\">\n                      <span class=\"btn btn-primary btn-file\">\n                          Browse&hellip; <input type=\"file\" id=\"file\" name=\"files[]\" multiple accept=\"application/pdf\">\n                      </span>\n                  </span>\n                  <input type=\"text\" class=\"form-control\" readonly>\n                </div>\n\n                <!-- fix for the fact that IE11 is trash https://blog.yorkxin.org/posts/2014/02/06/ajax-with-formdata-is-broken-on-ie10-ie11/ -->\n                <input type=\"hidden\" name=\"_dontcare\">\n\n                <button type=\"submit\" class=\"btn btn-default\">Import</button>\n              </form>\n\n            </div>\n            <div id=\"progress-container\">\n            </div>\n              <hr>\n\n              <div id=\"library-container\">\n                <h4>Imported PDFs</h4>\n\n                <div id=\"file-list-container\">\n                <table class=\"table file-list tablesorter\" id=\"fileTable\">\n                  <thead>\n                    <tr>\n                      <th>File Name</th>\n                      <th style=\"min-width: 100px;\">Size</th>\n                      <th>Pages</th>\n                      <th style=\"min-width: 150px;\">Date Added</th>\n                      <th>Remove</th>\n                      <th>Process</th>\n                    </tr>\n                  </thead>\n                  <tbody id=\"uploaded-files-container\">\n                  </tbody>\n                </table>\n                </div>\n              </div>\n\n          <hr />\n          <p style=\"text-size: small;\">If you have several PDFs with the same layout, you can select the appropriate regions once, then save the selections as a Tabula Template from the Select Tables page. If someone has shared a template with you, you can upload it to Tabula at the <a href=\"/mytemplates\">My Templates page</a>.</p>\n\n          </div> <!-- /jumbotron -->\n        </div> <!-- /container -->\n\n        <!-- we are using this here: http://www.abeautifulsite.net/whipping-file-inputs-into-shape-with-bootstrap-3/ -->\n        <nestedscript type=\"text/javascript\" src=\"js/vendor/upload-group.js\"></nestedscript>\n        <nestedscript type=\"text/javascript\" src=\"js/vendor/jquery.tablesorter.min.js\"></nestedscript>\n        <nestedscript type=\"text/javascript\" src=\"js/vendor/spin.min.js\"></nestedscript>\n      </script>\n\n      <script type=\"text/template\" id=\"uploaded-file-template\">\n        <td><a href='/pdf/<%= id %>'><%= original_filename %></a></td>\n        <td><%= size ? Math.floor(size / 1024) : '??' %> kB</td>\n        <td><%= page_count || '??' %></td>\n        <td><%= new Date(parseInt(time) * 1000).toUTCString().slice(5, -7) %></td>\n        <td><a href=\"javascript:\"><span data-filename=<%= original_filename %> data-pdfid=<%= id %> class=\"glyphicon glyphicon-remove delete-pdf\"></span></a></td>\n        <td><a href=\"pdf/<%= id %>\"><button type=\"button\" class=\"btn btn-sm btn-success\">Extract Data</button></a></td>\n      </script>\n\n      <script type=\"text/template\" id=\"saved-template-library-item-template\">\n        <td><span class=\"template-name\"><%= name %></span> <a href=\"javascript:\"><span data-name=<%= name %> data-templateid=<%= id %> class=\"glyphicon glyphicon-pencil edit-template-name\"></span></a></td>\n        <td><%= selection_count %> selection<%= selection_count == \"!\" ? '' : 's' %></td>\n        <td><%= page_count || '??' %></td>\n        <td><%= new Date(parseInt(time) * 1000).toUTCString().slice(5, -7) %></td>\n        <td><a href=\"javascript:\"><span data-name=<%= name %> data-templateid=<%= id %> class=\"glyphicon glyphicon-remove delete-template\"></span></a></td>\n        <td>\n          <form class=\"template-download-form\" action=\"templates/<%= id %>.json\" method=\"get\" style=\"margin-bottom: 0;\">\n            <button type=\"submit\" class=\"btn btn-default\" data-action=>\n              <span class=\"glyphicon glyphicon-download-alt download-template\"></span>\n              Download\n            </button>\n          </form>\n        </td>\n      </script>\n\n      <script type=\"text/template\" id=\"upload-error-template\" >\n        <div class=\"container-fluid\">\n          <div class=\"row-fluid\">\n            <div class=\"span6 offset3\">\n              <div class=\"hero-unit\">\n                <h1>Tabula</h1>\n                <h2>Upload Error</h2>\n                <p><span id=\"message\"><%= message %></span></p>\n              </div> <!-- /hero-unit -->\n            </div>\n          </div>\n        </div>\n      </script>\n\n      <script type=\"text/template\" id=\"about-template\">\n        <div class=\"container\">\n          <div class=\"jumbotron about\">\n\n            <h1>About Tabula</h1>\n            <p>Tabula is a tool for liberating data tables trapped inside PDF files.</p>\n\n            <p>Tabula was created by journalists for journalists and anyone else working with data locked away in PDFs. Tabula will always be free and open source.</p>\n            <p>If you’ve ever tried to do anything with data provided to you in PDFs, you know how painful it is — there's no easy way to copy-and-paste rows of data out of PDF files. Tabula allows you to extract that data into a CSV or Microsoft Excel spreadsheet using a simple, easy-to-use interface. Tabula works on Mac, Windows and Linux.</p>\n            <p>Caveat: Tabula only works on text-based PDFs, not scanned documents. If you can click-and-drag to select text in your table in a PDF viewer (even if the output is unorganized trash), then your PDF is text-based and Tabula should work.</p>\n            <p><strong>Security Concerns?</strong> Tabula is designed with security in mind. Your PDF and the extracted data never touch the net -- when you use Tabula, as long as your browser's URL bar says \"localhost\" or \"127.0.0.1\", all processing takes place on your local machine. Tabula does download a list of Tabula versions from our server to alert you if Tabula has been updated (and we use hits to that list to count how often Tabula is being used); it also downloads a few badges and assets from the web.</p>\n\n            <h2>Who Uses Tabula?</h2>\n            <p>Tabula is used to power investigative reporting at news organizations of all sizes, including ProPublica, The Times of London, Foreign Policy, La Nación (Argentina) and the St. Paul (MN) Pioneer Press.</p>\n            <p>Grassroots organizations like SchoolCuts.org rely on Tabula to turn clunky documents into human-friendly public resources.</p>\n            <p>And researchers of all kinds use Tabula to turn PDF reports into Excel spreadsheets, CSVs, and JSON files for use in analysis and database applications.</p>\n\n            <h2>Credits</h2>\n            <p>Tabula was created by <a href=\"https://jazzido.com/\" target=\"_blank\">Manuel Aristarán</a>, <a href=\"https://mike.tig.as/\" target=\"_blank\">Mike Tigas</a> and <a href=\"http://jeremybmerrill.com/\" target=\"_blank\">Jeremy B. Merrill</a> with the support of <a href=\"https://www.propublica.org\">ProPublica</a>, <a href=\"http://blogs.lanacion.com.ar/data/\">La Nación DATA</a>, <a href=\"https://opennews.org/\">Knight-Mozilla OpenNews</a>, <a href=\"http://www.nytimes.com\">The New York Times</a>, <a href=\"http://knightlab.northwestern.edu/\">Northwestern University Knight Lab</a>, <a href=\"http://www.knightfoundation.org/\">The Knight Foundation</a>, and <a href=\"https://shuttleworthfoundation.org/\">The Shuttleworth Foundation</a>. Tabula was designed by <a href=\"http://jasondas.com\">Jason Das.</a></p>\n          </div> <!-- /jumbotron -->\n        </div> <!-- /container -->\n       </script>\n\n      <script type=\"text/templates\" id=\"templates-template\">\n        <div class=\"container\">\n          <div class=\"jumbotron help\">\n            <h1>My Saved Templates</h1>\n            <p style=\"font-size: small;\">If you have several PDFs with the same layout, you can select the appropriate regions once, then save the selections as a Tabula Template, and load it in subsequent PDFs. You can see your saved templates here; you can also rename and delete them. If someone has shared a template with you, you can import it to Tabula here.</p>\n            <p>To use a template, <a href=\"\">upload a file</a> or select it from <a href=\"\">My Files</a>.</p>\n            <div id=\"template-library-container\">\n              <div id=\"file-list-container\">\n              <table class=\"table file-list\" id=\"templateTable\">\n                <thead>\n                  <tr>\n                    <th>Template Name</th>\n                    <th>Selection Count</th>\n                    <th>Page Count</th>\n                    <th>Date Added</th>\n                    <th>Remove</th>\n                    <th>Download</th>\n                  </tr>\n                </thead>\n                <tbody id=\"saved-templates-container\">\n                </tbody>\n              </table>\n              </div>\n            </div>\n\n            <div id=\"template-upload-form-container\">\n              <h2>Import one or more Tabula Templates</h2>\n              <p style=\"font-size: small;\">Once you save a Tabula Template, it'll appear here.</p>\n              <form id=\"uploadtemplate\" action=\"templates/upload.json\" method=\"post\" enctype=\"multipart/form-data\" class=\"form-inline\">\n\n                <div class=\"input-group\">\n                  <!-- we are using this here: http://www.abeautifulsite.net/whipping-file-inputs-into-shape-with-bootstrap-3/ -->\n                  <span class=\"input-group-btn\">\n                      <span class=\"btn btn-primary btn-file\">\n                          Browse&hellip; <input type=\"file\" id=\"file\" name=\"files[]\" multiple accept=\"application/json\">\n                      </span>\n                  </span>\n                  <input type=\"text\" class=\"form-control\" readonly>\n                </div>\n\n                <!-- fix for the fact that IE11 is trash https://blog.yorkxin.org/posts/2014/02/06/ajax-with-formdata-is-broken-on-ie10-ie11/ -->\n                <input type=\"hidden\" name=\"_dontcare\">\n\n                <button type=\"submit\" class=\"btn btn-default\">Import</button>\n              </form>\n\n            </div>\n          </div> <!-- /jumbotron -->\n        </div> <!-- /container -->\n        <nestedscript type=\"text/javascript\" src=\"js/vendor/upload-group.js\"></nestedscript>\n        <nestedscript type=\"text/javascript\" src=\"js/vendor/jquery.tablesorter.min.js\"></nestedscript>\n      </script>\n\n\n      <script type=\"text/template\" id=\"help-template\">\n        <div class=\"container\">\n          <div class=\"jumbotron help\">\n          <h3 name=\"howto\">How to Use Tabula</h3>\n          <ol>\n            <li>Upload a PDF file containing a data table.</li>\n            <li>Select the table by clicking the top left corner of a table and dragging the mouse to the bottom right corner, until all of the data is included in the shaded selection area.</li>\n            <li>A window will then appear containing your data. Inspect the data to make sure it looks correct. If data is missing, you may have to slightly expand your selection.</li>\n            <li>Click the Download button.</li>\n            <li>Now you can work with your data as text file or a spreadsheet rather than a PDF! <br>\n            (You can open the downloaded file in Microsoft Excel or the free <a href=\"http://www.libreoffice.org/discover/calc/\">LibreOffice Calc</a>)<p></p></li>\n          </ol>\n          <p>Note: Tabula only works on text-based PDFs, not scanned documents.</p>\n          <h3 name=\"trouble\">Having trouble with Tabula?</h3>\n          <ol>\n          <li><strong>Tabula said \"Sorry, your PDF file is image-based\" -- what does that mean?</strong> Your PDF does not have any embedded text. It might have been scanned from paper. Tabula is not able to extract any data from image-based PDFs. You can try OCRing the PDF with a tool like Adobe Acrobat Pro (paid), Tesseract, <a href=\"http://www.tobias-elze.de/pdfsandwich/\">PDFSandwich</a> (Mac/Linux, free) or <a href=\"https://code.google.com/p/lime-ocr/\">Lime OCR</a> (Windows, free) and then trying Tabula again.</li>\n          <li><strong>Some columns of my table are combined. What can I do?</strong> Tabula sometimes uses \"streams\" of whitespace to recreate your table's structure. If headers span multiple columns, they're probably causing a problem. Try excluding them from your selection (or selecting them separately). </li>\n          <li><strong>Some columns of my table are combined. And the headers aren't the problem! What <em>else</em> can I do?</strong> Tabula has two extraction methods. It tries to guess which one is right for document, but it's wrong sometimes. Try selecting the other (of \"stream\" and \"lattice\"), on the left in extraction mode, to see if that fixes the problem.</li>\n          <li><strong>Tabula helps, but my extracted data isn't in the layout I want! How can I fix <em>that</em>?</strong> Tabula tries to recreate the table structure of the original document. You can think of Tabula as a data <em>extraction</em> tool rather than a data <em>transformation</em> tool. If you want to clean and transform your exported CSV or TSV, tools such as <a href=\"http://openrefine.org/\">OpenRefine</a> or a spreadsheet program might be a good place to start.</li>\n          <li><strong>Tabula's taking too long!</strong> Sorry! Tabula has to do a lot of weird math to reconstruct your table. Tabula's command-line counterpart, <a href=\"https://www.github.com/tabulapdf/tabula-extractor\">tabula-extractor</a> is faster, but a little harder to use. You might give it a try.</li>\n          <!-- li><strong>I had some other problem!</strong> Sorry! You can <a href=\"https://www.github.com/tabulapdf/tabula/issues/new\">report it to us here</a>. Be sure to include your PDF, either as a link or attached to the issue -- or email it to <a href=\"about\">one of the Tabula creators.</a> </li -->\n          </ol>\n\n          </div> <!-- /jumbotron -->\n        </div> <!-- /container -->\n       </script>\n       <script type=\"text/template\" id=\"notifications-approval-template\">\n          <div id=\"notifications-approval-clicky\">\n            Tabula can check for new versions and notifications from the developers and tell you about them. We count these requests to get a rough estimate of how many times Tabula is used per day (instead of Google Analytics). We never receive any information about what PDFs you extract with Tabula.\n            <input type=\"button\" id=\"notifications-approval-okay\" value=\"Okay! Notify me and count me.\" />\n            <input type=\"button\" id=\"notifications-approval-opt-out\" value=\"No thanks\" />\n            <a id=\"notifications-approval-close\" >✕</a>\n          </div>\n       </script>\n\n    </div> <!-- /templates -->\n\n\n\n\n    <!-- Bootstrap core JavaScript\n    ================================================== -->\n    <!-- Placed at the end of the document so the pages load faster -->\n\n    </script> <!-- TODO: move this to tabula.js, only run it if we're in upload page viewer -->\n\n    <script type=\"text/javascript\" src=\"js/tabula.js?_cachebuster=201510300905\"></script> <!-- actually starts Tabula -->\n    <script type=\"text/javascript\" src=\"js/template_library.js?_cachebuster=201510300905\"></script> <!-- needed on almost all pages -->\n\n  </body>\n</html>\n"
  },
  {
    "path": "webapp/static/css/_bootstrap-variables.scss",
    "content": "// Override Bootstrap variables here (defaults from bootstrap-sass v3.3.1.0):\n\n// When true, asset path helpers are used, otherwise the regular CSS `url()` is used.\n// When there no function is defined, `fn('')` is parsed as string that equals the right hand side\n// NB: in Sass 3.3 there is a native function: function-exists(twbs-font-path)\n// $bootstrap-sass-asset-helper: (twbs-font-path(\"\") != unquote('twbs-font-path(\"\")'))\n\n//\n// Variables\n// --------------------------------------------------\n\n//== Colors\n//\n//## Gray and brand colors for use across Bootstrap.\n\n// $gray-base:              #000\n// $gray-darker:            lighten($gray-base, 13.5%) // #222\n// $gray-dark:              lighten($gray-base, 20%)   // #333\n// $gray:                   lighten($gray-base, 33.5%) // #555\n// $gray-light:             lighten($gray-base, 46.7%) // #777\n// $gray-lighter:           lighten($gray-base, 93.5%) // #eee\n\n// $brand-primary:         darken(#428bca, 6.5%)\n// $brand-success:         #5cb85c\n// $brand-info:            #5bc0de\n// $brand-warning:         #f0ad4e\n// $brand-danger:          #d9534f\n\n//== Scaffolding\n//\n//## Settings for some of the most global styles.\n\n//** Background color for `<body>`.\n// $body-bg:               #fff\n//** Global text color on `<body>`.\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//** Link hover decoration.\n// $link-hover-decoration: underline\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 `<code>`, `<kbd>`, and `<pre>`.\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 `<body>`.\n// $headings-font-family:    inherit\n// $headings-font-weight:    500\n// $headings-line-height:    1.1\n// $headings-color:          inherit\n\n//== Iconography\n//\n//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.\n\n//** Load fonts from this directory.\n\n// [converter] Asset helpers such as Sprockets and Node.js Mincer do not resolve relative paths\n// $icon-font-path: if($bootstrap-sass-asset-helper, \"bootstrap/\", \"../fonts/bootstrap/\")\n\n//** File name for all font files.\n// $icon-font-name:          \"glyphicons-halflings-regular\"\n//** Element ID within SVG icon file.\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//== Tables\n//\n//## Customizes the `.table` component with basic values, each used across all table variations.\n\n//** Padding for `<th>`s and `<td>`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//== 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//== Forms\n//\n//##\n\n//** `<input>` background color\n// $input-bg:                       #fff\n//** `<input disabled>` background color\n// $input-bg-disabled:              $gray-lighter\n\n//** Text color for `<input>`s\n// $input-color:                    $gray\n//** `<input>` border color\n// $input-border:                   #ccc\n\n// TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4\n//** Default `.form-control` border radius\n// $input-border-radius:            $border-radius-base\n//** Large `.form-control` border radius\n// $input-border-radius-large:      $border-radius-large\n//** Small `.form-control` border radius\n// $input-border-radius-small:      $border-radius-small\n\n//** Border color for inputs on focus\n// $input-border-focus:             #66afe9\n\n//** Placeholder text color\n// $input-color-placeholder:        #999\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//** Disabled cursor for form controls and buttons.\n// $cursor-disabled:                not-allowed\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//** Deprecated `$dropdown-caret-color` as of v3.1.0\n// $dropdown-caret-color:           #000\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:           1060\n// $zindex-tooltip:           1070\n// $zindex-navbar-fixed:      1030\n// $zindex-modal:             1040\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//** Deprecated `$screen-xs` as of v3.0.1\n// $screen-xs:                  480px\n//** Deprecated `$screen-xs-min` as of v3.2.0\n// $screen-xs-min:              $screen-xs\n//** Deprecated `$screen-phone` as of v3.0.1\n// $screen-phone:               $screen-xs-min\n\n// Small screen / tablet\n//** Deprecated `$screen-sm` as of v3.0.1\n// $screen-sm:                  768px\n// $screen-sm-min:              $screen-sm\n//** Deprecated `$screen-tablet` as of v3.0.1\n// $screen-tablet:              $screen-sm-min\n\n// Medium screen / desktop\n//** Deprecated `$screen-md` as of v3.0.1\n// $screen-md:                  992px\n// $screen-md-min:              $screen-md\n//** Deprecated `$screen-desktop` as of v3.0.1\n// $screen-desktop:             $screen-md-min\n\n// Large screen / wide desktop\n//** Deprecated `$screen-lg` as of v3.0.1\n// $screen-lg:                  1200px\n// $screen-lg-min:              $screen-lg\n//** Deprecated `$screen-lg-desktop` as of v3.0.1\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//== 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//== 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//== 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// Inverted navbar\n// Reset inverted navbar basics\n// $navbar-inverse-color:                      lighten($gray-light, 15%)\n// $navbar-inverse-bg:                         #222\n// $navbar-inverse-border:                     darken($navbar-inverse-bg, 10%)\n\n// Inverted navbar links\n// $navbar-inverse-link-color:                 lighten($gray-light, 15%)\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//== 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//== 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//== 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//== 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//== 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//== 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(adjust-hue($state-success-bg, -10), 5%)\n\n// $state-info-text:                #31708f\n// $state-info-bg:                  #d9edf7\n// $state-info-border:              darken(adjust-hue($state-info-bg, -10), 7%)\n\n// $state-warning-text:             #8a6d3b\n// $state-warning-bg:               #fcf8e3\n// $state-warning-border:           darken(adjust-hue($state-warning-bg, -10), 5%)\n\n// $state-danger-text:              #a94442\n// $state-danger-bg:                #f2dede\n// $state-danger-border:            darken(adjust-hue($state-danger-bg, -10), 5%)\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//== 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:                 $popover-bg\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:           fade_in($popover-border-color, 0.05)\n//** Popover outer arrow fallback color\n// $popover-arrow-outer-fallback-color:  darken($popover-fallback-border-color, 20%)\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//== Modals\n//\n//##\n\n//** Padding applied to the modal body\n// $modal-inner-padding:         15px\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//== 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//== 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//** Variable for setting rounded corners on progress bar.\n// $progress-border-radius:      $border-radius-base\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//== 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 items on hover\n// $list-group-hover-bg:           #f5f5f5\n//** Text color of active list items\n// $list-group-active-color:       $component-active-color\n//** Background color of active list items\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//** Text color for content within active list items\n// $list-group-active-text-color:  lighten($list-group-active-bg, 40%)\n\n//** Text color of disabled list items\n// $list-group-disabled-color:      $gray-light\n//** Background color of disabled list items\n// $list-group-disabled-bg:         $gray-lighter\n//** Text color for content within disabled list items\n// $list-group-disabled-text-color: $list-group-disabled-color\n\n// $list-group-link-color:         #555\n// $list-group-link-hover-color:   $list-group-link-color\n// $list-group-link-heading-color: #333\n\n//== Panels\n//\n//##\n\n// $panel-bg:                    #fff\n// $panel-body-padding:          15px\n// $panel-heading-padding:       10px 15px\n// $panel-footer-padding:        $panel-heading-padding\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//== 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//== Wells\n//\n//##\n\n// $well-bg:                     #f5f5f5\n// $well-border:                 darken($well-bg, 7%)\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//== 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//== 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//== Close\n//\n//##\n\n// $close-font-weight:           bold\n// $close-color:                 #000\n// $close-text-shadow:           0 1px 0 #fff\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//== Type\n//\n//##\n\n//** Horizontal offset for forms and lists.\n// $component-offset-horizontal: 180px\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//** Width of horizontal description list titles\n// $dl-horizontal-offset:        $component-offset-horizontal\n//** Horizontal line color.\n// $hr-border:                   $gray-lighter\n"
  },
  {
    "path": "webapp/static/css/selectors.css",
    "content": ".thumbnail-list li div.selection-show {\n  position: absolute;\n  border: 1px dashed red;\n  display: none;\n  pointer-events: none;\n}\n\n/* selections */\n.repeat-lassos-group {\n  position: absolute;\n  right: -185px;\n  bottom: -35px;\n}\n\n/* rectangularSelector.js classes */\n.selection-box, .table-region {\n  position: absolute;\n  border: 1px dashed rgba(255, 87, 0, 0.8);\n  background: rgba(255, 87, 0, 0.2);\n  box-sizing: border-box;\n}\n.selection-box:hover, .table-region:hover {\n  cursor: pointer;\n}\n\n.selection-box {\n  z-index: 42;\n  width: 0;\n  height: 0;\n  visibility: hidden;\n}\n\n.table-region {\n  top: 0;\n  left: 0;\n  z-index: 21;\n}\n\ndiv.table-region .resize-handle {\n  position: absolute;\n}\n\ndiv.table-region .n-border {\n  width: calc(100% - 10px);\n  top: -5px;\n  left: 5px;\n  height: 10px;\n}\n\ndiv.table-region .s-border {\n  width: calc(100% - 10px);\n  bottom: -5px;\n  left: 5px;\n  height: 10px;\n}\n\ndiv.table-region .w-border {\n  height: calc(100% - 10px);\n  left: -5px;\n  top: 5px;\n  width: 10px;\n}\n\ndiv.table-region .e-border {\n  height: calc(100% - 10px);\n  top: 5px;\n  right: -5px;\n  width: 10px;\n}\n\ndiv.table-region .nw-border {\n  width: 10px;\n  height: 10px;\n  top: -5px;\n  left: -5px;\n}\n\ndiv.table-region .ne-border {\n  width: 10px;\n  height: 10px;\n  top: -5px;\n  right: -5px;\n}\n\ndiv.table-region .sw-border {\n  width: 10px;\n  height: 10px;\n  bottom: -5px;\n  left: -5px;\n}\n\ndiv.table-region .se-border {\n  width: 10px;\n  height: 10px;\n  bottom: -5px;\n  right: -5px;\n}\n\ndiv.table-region .n-border:hover {\n  cursor: n-resize;\n}\n\ndiv.table-region .nw-border:hover {\n  cursor: nw-resize;\n}\n\ndiv.table-region .ne-border:hover {\n  cursor: ne-resize;\n}\n\ndiv.table-region .s-border:hover {\n  cursor: s-resize;\n}\n\ndiv.table-region .sw-border:hover {\n  cursor: sw-resize;\n}\n\ndiv.table-region .se-border:hover {\n  cursor: se-resize;\n}\n\ndiv.table-region .w-border:hover {\n  cursor: w-resize;\n}\n\ndiv.table-region .e-border:hover {\n  cursor: e-resize;\n}\n\ndiv.table-region button[name=close] {\n  font-weight: bold;\n  border: 0;\n  background-color: transparent;\n  padding: 0;\n  font-size: 20px;\n  position: relative;\n  top: -25px;\n  left: 100%;\n  margin-left: 5px;\n}\n\ndiv.table-region button[name=close]:hover {\n  color: red;\n}\n"
  },
  {
    "path": "webapp/static/css/styles.css",
    "content": "@charset \"UTF-8\";\n/*!\n * WARNING: Don't edit this file by hand! Instead, you should be using Compass.\n * Edit the file in webapp/static/sass/styles.scss (or webapp/static/sass/selectors.scss)\n * Then, run `$ compass watch` to automatically re-compile the scss file into \"normal\" CSS on save.\n * Alternatively, run `$ compass compile` to re-compile the SCSS once.\n */\n/*! normalize.css v3.0.1 | MIT License | git.io/normalize */\nhtml {\n  font-family: sans-serif;\n  -ms-text-size-adjust: 100%;\n  -webkit-text-size-adjust: 100%;\n}\n\nbody {\n  margin: 0;\n}\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nnav,\nsection,\nsummary {\n  display: block;\n}\n\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block;\n  vertical-align: baseline;\n}\n\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n\n[hidden],\ntemplate {\n  display: none;\n}\n\na {\n  background: transparent;\n}\n\na:active,\na:hover {\n  outline: 0;\n}\n\nabbr[title] {\n  border-bottom: 1px dotted;\n}\n\nb,\nstrong {\n  font-weight: bold;\n}\n\ndfn {\n  font-style: italic;\n}\n\nh1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\n\nmark {\n  background: #ff0;\n  color: #000;\n}\n\nsmall {\n  font-size: 80%;\n}\n\nsub,\nsup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\n\nsup {\n  top: -0.5em;\n}\n\nsub {\n  bottom: -0.25em;\n}\n\nimg {\n  border: 0;\n}\n\nsvg:not(:root) {\n  overflow: hidden;\n}\n\nfigure {\n  margin: 1em 40px;\n}\n\nhr {\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n  height: 0;\n}\n\npre {\n  overflow: auto;\n}\n\ncode,\nkbd,\npre,\nsamp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  color: inherit;\n  font: inherit;\n  margin: 0;\n}\n\nbutton {\n  overflow: visible;\n}\n\nbutton,\nselect {\n  text-transform: none;\n}\n\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button;\n  cursor: pointer;\n}\n\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default;\n}\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  border: 0;\n  padding: 0;\n}\n\ninput {\n  line-height: normal;\n}\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  box-sizing: border-box;\n  padding: 0;\n}\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\n\ninput[type=\"search\"] {\n  -webkit-appearance: textfield;\n  -moz-box-sizing: content-box;\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n\nfieldset {\n  border: 1px solid #c0c0c0;\n  margin: 0 2px;\n  padding: 0.35em 0.625em 0.75em;\n}\n\nlegend {\n  border: 0;\n  padding: 0;\n}\n\ntextarea {\n  overflow: auto;\n}\n\noptgroup {\n  font-weight: bold;\n}\n\ntable {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\ntd,\nth {\n  padding: 0;\n}\n\n@media print {\n  * {\n    text-shadow: none !important;\n    color: #000 !important;\n    background: transparent !important;\n    box-shadow: none !important;\n  }\n\n  a,\n  a:visited {\n    text-decoration: underline;\n  }\n\n  a[href]:after {\n    content: \" (\" attr(href) \")\";\n  }\n\n  abbr[title]:after {\n    content: \" (\" attr(title) \")\";\n  }\n\n  a[href^=\"javascript:\"]:after,\n  a[href^=\"#\"]:after {\n    content: \"\";\n  }\n\n  pre,\n  blockquote {\n    border: 1px solid #999;\n    page-break-inside: avoid;\n  }\n\n  thead {\n    display: table-header-group;\n  }\n\n  tr,\n  img {\n    page-break-inside: avoid;\n  }\n\n  img {\n    max-width: 100% !important;\n  }\n\n  p,\n  h2,\n  h3 {\n    orphans: 3;\n    widows: 3;\n  }\n\n  h2,\n  h3 {\n    page-break-after: avoid;\n  }\n\n  select {\n    background: #fff !important;\n  }\n\n  .navbar {\n    display: none;\n  }\n\n  .table td,\n  .table th {\n    background-color: #fff !important;\n  }\n\n  .btn > .caret,\n  .dropup > .btn > .caret {\n    border-top-color: #000 !important;\n  }\n\n  .label {\n    border: 1px solid #000;\n  }\n\n  .table {\n    border-collapse: collapse !important;\n  }\n\n  .table-bordered th,\n  .table-bordered td {\n    border: 1px solid #ddd !important;\n  }\n}\n@font-face {\n  font-family: 'Glyphicons Halflings';\n  src: url(webapp/fonts/bootstrap/glyphicons-halflings-regular.eot);\n  src: url(webapp/fonts/bootstrap/glyphicons-halflings-regular.eot?#iefix) format(\"embedded-opentype\"), url(webapp/fonts/bootstrap/glyphicons-halflings-regular.woff) format(\"woff\"), url(webapp/fonts/bootstrap/glyphicons-halflings-regular.ttf) format(\"truetype\"), url(webapp/fonts/bootstrap/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format(\"svg\");\n}\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.glyphicon-asterisk:before {\n  content: \"\\2a\";\n}\n\n.glyphicon-plus:before {\n  content: \"\\2b\";\n}\n\n.glyphicon-euro:before {\n  content: \"\\20ac\";\n}\n\n.glyphicon-minus:before {\n  content: \"\\2212\";\n}\n\n.glyphicon-cloud:before {\n  content: \"\\2601\";\n}\n\n.glyphicon-envelope:before {\n  content: \"\\2709\";\n}\n\n.glyphicon-pencil:before {\n  content: \"\\270f\";\n}\n\n.glyphicon-glass:before {\n  content: \"\\e001\";\n}\n\n.glyphicon-music:before {\n  content: \"\\e002\";\n}\n\n.glyphicon-search:before {\n  content: \"\\e003\";\n}\n\n.glyphicon-heart:before {\n  content: \"\\e005\";\n}\n\n.glyphicon-star:before {\n  content: \"\\e006\";\n}\n\n.glyphicon-star-empty:before {\n  content: \"\\e007\";\n}\n\n.glyphicon-user:before {\n  content: \"\\e008\";\n}\n\n.glyphicon-film:before {\n  content: \"\\e009\";\n}\n\n.glyphicon-th-large:before {\n  content: \"\\e010\";\n}\n\n.glyphicon-th:before {\n  content: \"\\e011\";\n}\n\n.glyphicon-th-list:before {\n  content: \"\\e012\";\n}\n\n.glyphicon-ok:before {\n  content: \"\\e013\";\n}\n\n.glyphicon-remove:before {\n  content: \"\\e014\";\n}\n\n.glyphicon-zoom-in:before {\n  content: \"\\e015\";\n}\n\n.glyphicon-zoom-out:before {\n  content: \"\\e016\";\n}\n\n.glyphicon-off:before {\n  content: \"\\e017\";\n}\n\n.glyphicon-signal:before {\n  content: \"\\e018\";\n}\n\n.glyphicon-cog:before {\n  content: \"\\e019\";\n}\n\n.glyphicon-trash:before {\n  content: \"\\e020\";\n}\n\n.glyphicon-home:before {\n  content: \"\\e021\";\n}\n\n.glyphicon-file:before {\n  content: \"\\e022\";\n}\n\n.glyphicon-time:before {\n  content: \"\\e023\";\n}\n\n.glyphicon-road:before {\n  content: \"\\e024\";\n}\n\n.glyphicon-download-alt:before {\n  content: \"\\e025\";\n}\n\n.glyphicon-download:before {\n  content: \"\\e026\";\n}\n\n.glyphicon-upload:before {\n  content: \"\\e027\";\n}\n\n.glyphicon-inbox:before {\n  content: \"\\e028\";\n}\n\n.glyphicon-play-circle:before {\n  content: \"\\e029\";\n}\n\n.glyphicon-repeat:before {\n  content: \"\\e030\";\n}\n\n.glyphicon-refresh:before {\n  content: \"\\e031\";\n}\n\n.glyphicon-list-alt:before {\n  content: \"\\e032\";\n}\n\n.glyphicon-lock:before {\n  content: \"\\e033\";\n}\n\n.glyphicon-flag:before {\n  content: \"\\e034\";\n}\n\n.glyphicon-headphones:before {\n  content: \"\\e035\";\n}\n\n.glyphicon-volume-off:before {\n  content: \"\\e036\";\n}\n\n.glyphicon-volume-down:before {\n  content: \"\\e037\";\n}\n\n.glyphicon-volume-up:before {\n  content: \"\\e038\";\n}\n\n.glyphicon-qrcode:before {\n  content: \"\\e039\";\n}\n\n.glyphicon-barcode:before {\n  content: \"\\e040\";\n}\n\n.glyphicon-tag:before {\n  content: \"\\e041\";\n}\n\n.glyphicon-tags:before {\n  content: \"\\e042\";\n}\n\n.glyphicon-book:before {\n  content: \"\\e043\";\n}\n\n.glyphicon-bookmark:before {\n  content: \"\\e044\";\n}\n\n.glyphicon-print:before {\n  content: \"\\e045\";\n}\n\n.glyphicon-camera:before {\n  content: \"\\e046\";\n}\n\n.glyphicon-font:before {\n  content: \"\\e047\";\n}\n\n.glyphicon-bold:before {\n  content: \"\\e048\";\n}\n\n.glyphicon-italic:before {\n  content: \"\\e049\";\n}\n\n.glyphicon-text-height:before {\n  content: \"\\e050\";\n}\n\n.glyphicon-text-width:before {\n  content: \"\\e051\";\n}\n\n.glyphicon-align-left:before {\n  content: \"\\e052\";\n}\n\n.glyphicon-align-center:before {\n  content: \"\\e053\";\n}\n\n.glyphicon-align-right:before {\n  content: \"\\e054\";\n}\n\n.glyphicon-align-justify:before {\n  content: \"\\e055\";\n}\n\n.glyphicon-list:before {\n  content: \"\\e056\";\n}\n\n.glyphicon-indent-left:before {\n  content: \"\\e057\";\n}\n\n.glyphicon-indent-right:before {\n  content: \"\\e058\";\n}\n\n.glyphicon-facetime-video:before {\n  content: \"\\e059\";\n}\n\n.glyphicon-picture:before {\n  content: \"\\e060\";\n}\n\n.glyphicon-map-marker:before {\n  content: \"\\e062\";\n}\n\n.glyphicon-adjust:before {\n  content: \"\\e063\";\n}\n\n.glyphicon-tint:before {\n  content: \"\\e064\";\n}\n\n.glyphicon-edit:before {\n  content: \"\\e065\";\n}\n\n.glyphicon-share:before {\n  content: \"\\e066\";\n}\n\n.glyphicon-check:before {\n  content: \"\\e067\";\n}\n\n.glyphicon-move:before {\n  content: \"\\e068\";\n}\n\n.glyphicon-step-backward:before {\n  content: \"\\e069\";\n}\n\n.glyphicon-fast-backward:before {\n  content: \"\\e070\";\n}\n\n.glyphicon-backward:before {\n  content: \"\\e071\";\n}\n\n.glyphicon-play:before {\n  content: \"\\e072\";\n}\n\n.glyphicon-pause:before {\n  content: \"\\e073\";\n}\n\n.glyphicon-stop:before {\n  content: \"\\e074\";\n}\n\n.glyphicon-forward:before {\n  content: \"\\e075\";\n}\n\n.glyphicon-fast-forward:before {\n  content: \"\\e076\";\n}\n\n.glyphicon-step-forward:before {\n  content: \"\\e077\";\n}\n\n.glyphicon-eject:before {\n  content: \"\\e078\";\n}\n\n.glyphicon-chevron-left:before {\n  content: \"\\e079\";\n}\n\n.glyphicon-chevron-right:before {\n  content: \"\\e080\";\n}\n\n.glyphicon-plus-sign:before {\n  content: \"\\e081\";\n}\n\n.glyphicon-minus-sign:before {\n  content: \"\\e082\";\n}\n\n.glyphicon-remove-sign:before {\n  content: \"\\e083\";\n}\n\n.glyphicon-ok-sign:before {\n  content: \"\\e084\";\n}\n\n.glyphicon-question-sign:before {\n  content: \"\\e085\";\n}\n\n.glyphicon-info-sign:before {\n  content: \"\\e086\";\n}\n\n.glyphicon-screenshot:before {\n  content: \"\\e087\";\n}\n\n.glyphicon-remove-circle:before {\n  content: \"\\e088\";\n}\n\n.glyphicon-ok-circle:before {\n  content: \"\\e089\";\n}\n\n.glyphicon-ban-circle:before {\n  content: \"\\e090\";\n}\n\n.glyphicon-arrow-left:before {\n  content: \"\\e091\";\n}\n\n.glyphicon-arrow-right:before {\n  content: \"\\e092\";\n}\n\n.glyphicon-arrow-up:before {\n  content: \"\\e093\";\n}\n\n.glyphicon-arrow-down:before {\n  content: \"\\e094\";\n}\n\n.glyphicon-share-alt:before {\n  content: \"\\e095\";\n}\n\n.glyphicon-resize-full:before {\n  content: \"\\e096\";\n}\n\n.glyphicon-resize-small:before {\n  content: \"\\e097\";\n}\n\n.glyphicon-exclamation-sign:before {\n  content: \"\\e101\";\n}\n\n.glyphicon-gift:before {\n  content: \"\\e102\";\n}\n\n.glyphicon-leaf:before {\n  content: \"\\e103\";\n}\n\n.glyphicon-fire:before {\n  content: \"\\e104\";\n}\n\n.glyphicon-eye-open:before {\n  content: \"\\e105\";\n}\n\n.glyphicon-eye-close:before {\n  content: \"\\e106\";\n}\n\n.glyphicon-warning-sign:before {\n  content: \"\\e107\";\n}\n\n.glyphicon-plane:before {\n  content: \"\\e108\";\n}\n\n.glyphicon-calendar:before {\n  content: \"\\e109\";\n}\n\n.glyphicon-random:before {\n  content: \"\\e110\";\n}\n\n.glyphicon-comment:before {\n  content: \"\\e111\";\n}\n\n.glyphicon-magnet:before {\n  content: \"\\e112\";\n}\n\n.glyphicon-chevron-up:before {\n  content: \"\\e113\";\n}\n\n.glyphicon-chevron-down:before {\n  content: \"\\e114\";\n}\n\n.glyphicon-retweet:before {\n  content: \"\\e115\";\n}\n\n.glyphicon-shopping-cart:before {\n  content: \"\\e116\";\n}\n\n.glyphicon-folder-close:before {\n  content: \"\\e117\";\n}\n\n.glyphicon-folder-open:before {\n  content: \"\\e118\";\n}\n\n.glyphicon-resize-vertical:before {\n  content: \"\\e119\";\n}\n\n.glyphicon-resize-horizontal:before {\n  content: \"\\e120\";\n}\n\n.glyphicon-hdd:before {\n  content: \"\\e121\";\n}\n\n.glyphicon-bullhorn:before {\n  content: \"\\e122\";\n}\n\n.glyphicon-bell:before {\n  content: \"\\e123\";\n}\n\n.glyphicon-certificate:before {\n  content: \"\\e124\";\n}\n\n.glyphicon-thumbs-up:before {\n  content: \"\\e125\";\n}\n\n.glyphicon-thumbs-down:before {\n  content: \"\\e126\";\n}\n\n.glyphicon-hand-right:before {\n  content: \"\\e127\";\n}\n\n.glyphicon-hand-left:before {\n  content: \"\\e128\";\n}\n\n.glyphicon-hand-up:before {\n  content: \"\\e129\";\n}\n\n.glyphicon-hand-down:before {\n  content: \"\\e130\";\n}\n\n.glyphicon-circle-arrow-right:before {\n  content: \"\\e131\";\n}\n\n.glyphicon-circle-arrow-left:before {\n  content: \"\\e132\";\n}\n\n.glyphicon-circle-arrow-up:before {\n  content: \"\\e133\";\n}\n\n.glyphicon-circle-arrow-down:before {\n  content: \"\\e134\";\n}\n\n.glyphicon-globe:before {\n  content: \"\\e135\";\n}\n\n.glyphicon-wrench:before {\n  content: \"\\e136\";\n}\n\n.glyphicon-tasks:before {\n  content: \"\\e137\";\n}\n\n.glyphicon-filter:before {\n  content: \"\\e138\";\n}\n\n.glyphicon-briefcase:before {\n  content: \"\\e139\";\n}\n\n.glyphicon-fullscreen:before {\n  content: \"\\e140\";\n}\n\n.glyphicon-dashboard:before {\n  content: \"\\e141\";\n}\n\n.glyphicon-paperclip:before {\n  content: \"\\e142\";\n}\n\n.glyphicon-heart-empty:before {\n  content: \"\\e143\";\n}\n\n.glyphicon-link:before {\n  content: \"\\e144\";\n}\n\n.glyphicon-phone:before {\n  content: \"\\e145\";\n}\n\n.glyphicon-pushpin:before {\n  content: \"\\e146\";\n}\n\n.glyphicon-usd:before {\n  content: \"\\e148\";\n}\n\n.glyphicon-gbp:before {\n  content: \"\\e149\";\n}\n\n.glyphicon-sort:before {\n  content: \"\\e150\";\n}\n\n.glyphicon-sort-by-alphabet:before {\n  content: \"\\e151\";\n}\n\n.glyphicon-sort-by-alphabet-alt:before {\n  content: \"\\e152\";\n}\n\n.glyphicon-sort-by-order:before {\n  content: \"\\e153\";\n}\n\n.glyphicon-sort-by-order-alt:before {\n  content: \"\\e154\";\n}\n\n.glyphicon-sort-by-attributes:before {\n  content: \"\\e155\";\n}\n\n.glyphicon-sort-by-attributes-alt:before {\n  content: \"\\e156\";\n}\n\n.glyphicon-unchecked:before {\n  content: \"\\e157\";\n}\n\n.glyphicon-expand:before {\n  content: \"\\e158\";\n}\n\n.glyphicon-collapse-down:before {\n  content: \"\\e159\";\n}\n\n.glyphicon-collapse-up:before {\n  content: \"\\e160\";\n}\n\n.glyphicon-log-in:before {\n  content: \"\\e161\";\n}\n\n.glyphicon-flash:before {\n  content: \"\\e162\";\n}\n\n.glyphicon-log-out:before {\n  content: \"\\e163\";\n}\n\n.glyphicon-new-window:before {\n  content: \"\\e164\";\n}\n\n.glyphicon-record:before {\n  content: \"\\e165\";\n}\n\n.glyphicon-save:before {\n  content: \"\\e166\";\n}\n\n.glyphicon-open:before {\n  content: \"\\e167\";\n}\n\n.glyphicon-saved:before {\n  content: \"\\e168\";\n}\n\n.glyphicon-import:before {\n  content: \"\\e169\";\n}\n\n.glyphicon-export:before {\n  content: \"\\e170\";\n}\n\n.glyphicon-send:before {\n  content: \"\\e171\";\n}\n\n.glyphicon-floppy-disk:before {\n  content: \"\\e172\";\n}\n\n.glyphicon-floppy-saved:before {\n  content: \"\\e173\";\n}\n\n.glyphicon-floppy-remove:before {\n  content: \"\\e174\";\n}\n\n.glyphicon-floppy-save:before {\n  content: \"\\e175\";\n}\n\n.glyphicon-floppy-open:before {\n  content: \"\\e176\";\n}\n\n.glyphicon-credit-card:before {\n  content: \"\\e177\";\n}\n\n.glyphicon-transfer:before {\n  content: \"\\e178\";\n}\n\n.glyphicon-cutlery:before {\n  content: \"\\e179\";\n}\n\n.glyphicon-header:before {\n  content: \"\\e180\";\n}\n\n.glyphicon-compressed:before {\n  content: \"\\e181\";\n}\n\n.glyphicon-earphone:before {\n  content: \"\\e182\";\n}\n\n.glyphicon-phone-alt:before {\n  content: \"\\e183\";\n}\n\n.glyphicon-tower:before {\n  content: \"\\e184\";\n}\n\n.glyphicon-stats:before {\n  content: \"\\e185\";\n}\n\n.glyphicon-sd-video:before {\n  content: \"\\e186\";\n}\n\n.glyphicon-hd-video:before {\n  content: \"\\e187\";\n}\n\n.glyphicon-subtitles:before {\n  content: \"\\e188\";\n}\n\n.glyphicon-sound-stereo:before {\n  content: \"\\e189\";\n}\n\n.glyphicon-sound-dolby:before {\n  content: \"\\e190\";\n}\n\n.glyphicon-sound-5-1:before {\n  content: \"\\e191\";\n}\n\n.glyphicon-sound-6-1:before {\n  content: \"\\e192\";\n}\n\n.glyphicon-sound-7-1:before {\n  content: \"\\e193\";\n}\n\n.glyphicon-copyright-mark:before {\n  content: \"\\e194\";\n}\n\n.glyphicon-registration-mark:before {\n  content: \"\\e195\";\n}\n\n.glyphicon-cloud-download:before {\n  content: \"\\e197\";\n}\n\n.glyphicon-cloud-upload:before {\n  content: \"\\e198\";\n}\n\n.glyphicon-tree-conifer:before {\n  content: \"\\e199\";\n}\n\n.glyphicon-tree-deciduous:before {\n  content: \"\\e200\";\n}\n\n* {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n\n*:before,\n*:after {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n\nhtml {\n  font-size: 10px;\n  -webkit-tap-highlight-color: transparent;\n}\n\nbody {\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 14px;\n  line-height: 1.428571429;\n  color: #333333;\n  background-color: #fff;\n}\n\ninput,\nbutton,\nselect,\ntextarea {\n  font-family: inherit;\n  font-size: inherit;\n  line-height: inherit;\n}\n\na {\n  color: #428bca;\n  text-decoration: none;\n}\na:hover, a:focus {\n  color: #2a6496;\n  text-decoration: underline;\n}\na:focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n\nfigure {\n  margin: 0;\n}\n\nimg {\n  vertical-align: middle;\n}\n\n.img-responsive {\n  display: block;\n  width: 100% \\9;\n  max-width: 100%;\n  height: auto;\n}\n\n.img-rounded {\n  border-radius: 6px;\n}\n\n.img-thumbnail {\n  padding: 4px;\n  line-height: 1.428571429;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-radius: 4px;\n  -webkit-transition: all 0.2s ease-in-out;\n  -o-transition: all 0.2s ease-in-out;\n  transition: all 0.2s ease-in-out;\n  display: inline-block;\n  width: 100% \\9;\n  max-width: 100%;\n  height: auto;\n}\n\n.img-circle {\n  border-radius: 50%;\n}\n\nhr {\n  margin-top: 20px;\n  margin-bottom: 20px;\n  border: 0;\n  border-top: 1px solid #eeeeee;\n}\n\n.sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n}\n\n.sr-only-focusable:active, .sr-only-focusable:focus {\n  position: static;\n  width: auto;\n  height: auto;\n  margin: 0;\n  overflow: visible;\n  clip: auto;\n}\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n  font-family: inherit;\n  font-weight: 500;\n  line-height: 1.1;\n  color: inherit;\n}\nh1 small,\nh1 .small, h2 small,\nh2 .small, h3 small,\nh3 .small, h4 small,\nh4 .small, h5 small,\nh5 .small, h6 small,\nh6 .small,\n.h1 small,\n.h1 .small, .h2 small,\n.h2 .small, .h3 small,\n.h3 .small, .h4 small,\n.h4 .small, .h5 small,\n.h5 .small, .h6 small,\n.h6 .small {\n  font-weight: normal;\n  line-height: 1;\n  color: #777777;\n}\n\nh1, .h1,\nh2, .h2,\nh3, .h3 {\n  margin-top: 20px;\n  margin-bottom: 10px;\n}\nh1 small,\nh1 .small, .h1 small,\n.h1 .small,\nh2 small,\nh2 .small, .h2 small,\n.h2 .small,\nh3 small,\nh3 .small, .h3 small,\n.h3 .small {\n  font-size: 65%;\n}\n\nh4, .h4,\nh5, .h5,\nh6, .h6 {\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\nh4 small,\nh4 .small, .h4 small,\n.h4 .small,\nh5 small,\nh5 .small, .h5 small,\n.h5 .small,\nh6 small,\nh6 .small, .h6 small,\n.h6 .small {\n  font-size: 75%;\n}\n\nh1, .h1 {\n  font-size: 36px;\n}\n\nh2, .h2 {\n  font-size: 30px;\n}\n\nh3, .h3 {\n  font-size: 24px;\n}\n\nh4, .h4 {\n  font-size: 18px;\n}\n\nh5, .h5 {\n  font-size: 14px;\n}\n\nh6, .h6 {\n  font-size: 12px;\n}\n\np {\n  margin: 0 0 10px;\n}\n\n.lead {\n  margin-bottom: 20px;\n  font-size: 16px;\n  font-weight: 300;\n  line-height: 1.4;\n}\n@media (min-width: 768px) {\n  .lead {\n    font-size: 21px;\n  }\n}\n\nsmall,\n.small {\n  font-size: 85%;\n}\n\ncite {\n  font-style: normal;\n}\n\nmark,\n.mark {\n  background-color: #fcf8e3;\n  padding: .2em;\n}\n\n.text-left {\n  text-align: left;\n}\n\n.text-right {\n  text-align: right;\n}\n\n.text-center {\n  text-align: center;\n}\n\n.text-justify {\n  text-align: justify;\n}\n\n.text-nowrap {\n  white-space: nowrap;\n}\n\n.text-lowercase {\n  text-transform: lowercase;\n}\n\n.text-uppercase {\n  text-transform: uppercase;\n}\n\n.text-capitalize {\n  text-transform: capitalize;\n}\n\n.text-muted {\n  color: #777777;\n}\n\n.text-primary {\n  color: #428bca;\n}\n\na.text-primary:hover {\n  color: #3071a9;\n}\n\n.text-success {\n  color: #3c763d;\n}\n\na.text-success:hover {\n  color: #2b542c;\n}\n\n.text-info {\n  color: #31708f;\n}\n\na.text-info:hover {\n  color: #245269;\n}\n\n.text-warning {\n  color: #8a6d3b;\n}\n\na.text-warning:hover {\n  color: #66512c;\n}\n\n.text-danger {\n  color: #a94442;\n}\n\na.text-danger:hover {\n  color: #843534;\n}\n\n.bg-primary {\n  color: #fff;\n}\n\n.bg-primary {\n  background-color: #428bca;\n}\n\na.bg-primary:hover {\n  background-color: #3071a9;\n}\n\n.bg-success {\n  background-color: #dff0d8;\n}\n\na.bg-success:hover {\n  background-color: #c1e2b3;\n}\n\n.bg-info {\n  background-color: #d9edf7;\n}\n\na.bg-info:hover {\n  background-color: #afd9ee;\n}\n\n.bg-warning {\n  background-color: #fcf8e3;\n}\n\na.bg-warning:hover {\n  background-color: #f7ecb5;\n}\n\n.bg-danger {\n  background-color: #f2dede;\n}\n\na.bg-danger:hover {\n  background-color: #e4b9b9;\n}\n\n.page-header {\n  padding-bottom: 9px;\n  margin: 40px 0 20px;\n  border-bottom: 1px solid #eeeeee;\n}\n\nul,\nol {\n  margin-top: 0;\n  margin-bottom: 10px;\n}\nul ul,\nul ol,\nol ul,\nol ol {\n  margin-bottom: 0;\n}\n\n.list-unstyled, .list-inline {\n  padding-left: 0;\n  list-style: none;\n}\n\n.list-inline {\n  margin-left: -5px;\n}\n.list-inline > li {\n  display: inline-block;\n  padding-left: 5px;\n  padding-right: 5px;\n}\n\ndl {\n  margin-top: 0;\n  margin-bottom: 20px;\n}\n\ndt,\ndd {\n  line-height: 1.428571429;\n}\n\ndt {\n  font-weight: bold;\n}\n\ndd {\n  margin-left: 0;\n}\n\n.dl-horizontal dd:before, .dl-horizontal dd:after {\n  content: \" \";\n  display: table;\n}\n.dl-horizontal dd:after {\n  clear: both;\n}\n@media (min-width: 768px) {\n  .dl-horizontal dt {\n    float: left;\n    width: 160px;\n    clear: left;\n    text-align: right;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n  }\n  .dl-horizontal dd {\n    margin-left: 180px;\n  }\n}\n\nabbr[title],\nabbr[data-original-title] {\n  cursor: help;\n  border-bottom: 1px dotted #777777;\n}\n\n.initialism {\n  font-size: 90%;\n  text-transform: uppercase;\n}\n\nblockquote {\n  padding: 10px 20px;\n  margin: 0 0 20px;\n  font-size: 17.5px;\n  border-left: 5px solid #eeeeee;\n}\nblockquote p:last-child,\nblockquote ul:last-child,\nblockquote ol:last-child {\n  margin-bottom: 0;\n}\nblockquote footer,\nblockquote small,\nblockquote .small {\n  display: block;\n  font-size: 80%;\n  line-height: 1.428571429;\n  color: #777777;\n}\nblockquote footer:before,\nblockquote small:before,\nblockquote .small:before {\n  content: '\\2014 \\00A0';\n}\n\n.blockquote-reverse,\nblockquote.pull-right {\n  padding-right: 15px;\n  padding-left: 0;\n  border-right: 5px solid #eeeeee;\n  border-left: 0;\n  text-align: right;\n}\n.blockquote-reverse footer:before,\n.blockquote-reverse small:before,\n.blockquote-reverse .small:before,\nblockquote.pull-right footer:before,\nblockquote.pull-right small:before,\nblockquote.pull-right .small:before {\n  content: '';\n}\n.blockquote-reverse footer:after,\n.blockquote-reverse small:after,\n.blockquote-reverse .small:after,\nblockquote.pull-right footer:after,\nblockquote.pull-right small:after,\nblockquote.pull-right .small:after {\n  content: '\\00A0 \\2014';\n}\n\nblockquote:before,\nblockquote:after {\n  content: \"\";\n}\n\naddress {\n  margin-bottom: 20px;\n  font-style: normal;\n  line-height: 1.428571429;\n}\n\ncode,\nkbd,\npre,\nsamp {\n  font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\n\ncode {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #c7254e;\n  background-color: #f9f2f4;\n  border-radius: 4px;\n}\n\nkbd {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #fff;\n  background-color: #333;\n  border-radius: 3px;\n  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\nkbd kbd {\n  padding: 0;\n  font-size: 100%;\n  box-shadow: none;\n}\n\npre {\n  display: block;\n  padding: 9.5px;\n  margin: 0 0 10px;\n  font-size: 13px;\n  line-height: 1.428571429;\n  word-break: break-all;\n  word-wrap: break-word;\n  color: #333333;\n  background-color: #f5f5f5;\n  border: 1px solid #ccc;\n  border-radius: 4px;\n}\npre 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.pre-scrollable {\n  max-height: 340px;\n  overflow-y: scroll;\n}\n\n.container {\n  margin-right: auto;\n  margin-left: auto;\n  padding-left: 15px;\n  padding-right: 15px;\n}\n.container:before, .container:after {\n  content: \" \";\n  display: table;\n}\n.container:after {\n  clear: both;\n}\n@media (min-width: 768px) {\n  .container {\n    width: 750px;\n  }\n}\n@media (min-width: 992px) {\n  .container {\n    width: 970px;\n  }\n}\n@media (min-width: 1200px) {\n  .container {\n    width: 1170px;\n  }\n}\n\n.container-fluid {\n  margin-right: auto;\n  margin-left: auto;\n  padding-left: 15px;\n  padding-right: 15px;\n}\n.container-fluid:before, .container-fluid:after {\n  content: \" \";\n  display: table;\n}\n.container-fluid:after {\n  clear: both;\n}\n\n.row {\n  margin-left: -15px;\n  margin-right: -15px;\n}\n.row:before, .row:after {\n  content: \" \";\n  display: table;\n}\n.row:after {\n  clear: both;\n}\n\n.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 {\n  position: relative;\n  min-height: 1px;\n  padding-left: 15px;\n  padding-right: 15px;\n}\n\n.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 {\n  float: left;\n}\n\n.col-xs-1 {\n  width: 8.3333333333%;\n}\n\n.col-xs-2 {\n  width: 16.6666666667%;\n}\n\n.col-xs-3 {\n  width: 25%;\n}\n\n.col-xs-4 {\n  width: 33.3333333333%;\n}\n\n.col-xs-5 {\n  width: 41.6666666667%;\n}\n\n.col-xs-6 {\n  width: 50%;\n}\n\n.col-xs-7 {\n  width: 58.3333333333%;\n}\n\n.col-xs-8 {\n  width: 66.6666666667%;\n}\n\n.col-xs-9 {\n  width: 75%;\n}\n\n.col-xs-10 {\n  width: 83.3333333333%;\n}\n\n.col-xs-11 {\n  width: 91.6666666667%;\n}\n\n.col-xs-12 {\n  width: 100%;\n}\n\n.col-xs-pull-0 {\n  right: auto;\n}\n\n.col-xs-pull-1 {\n  right: 8.3333333333%;\n}\n\n.col-xs-pull-2 {\n  right: 16.6666666667%;\n}\n\n.col-xs-pull-3 {\n  right: 25%;\n}\n\n.col-xs-pull-4 {\n  right: 33.3333333333%;\n}\n\n.col-xs-pull-5 {\n  right: 41.6666666667%;\n}\n\n.col-xs-pull-6 {\n  right: 50%;\n}\n\n.col-xs-pull-7 {\n  right: 58.3333333333%;\n}\n\n.col-xs-pull-8 {\n  right: 66.6666666667%;\n}\n\n.col-xs-pull-9 {\n  right: 75%;\n}\n\n.col-xs-pull-10 {\n  right: 83.3333333333%;\n}\n\n.col-xs-pull-11 {\n  right: 91.6666666667%;\n}\n\n.col-xs-pull-12 {\n  right: 100%;\n}\n\n.col-xs-push-0 {\n  left: auto;\n}\n\n.col-xs-push-1 {\n  left: 8.3333333333%;\n}\n\n.col-xs-push-2 {\n  left: 16.6666666667%;\n}\n\n.col-xs-push-3 {\n  left: 25%;\n}\n\n.col-xs-push-4 {\n  left: 33.3333333333%;\n}\n\n.col-xs-push-5 {\n  left: 41.6666666667%;\n}\n\n.col-xs-push-6 {\n  left: 50%;\n}\n\n.col-xs-push-7 {\n  left: 58.3333333333%;\n}\n\n.col-xs-push-8 {\n  left: 66.6666666667%;\n}\n\n.col-xs-push-9 {\n  left: 75%;\n}\n\n.col-xs-push-10 {\n  left: 83.3333333333%;\n}\n\n.col-xs-push-11 {\n  left: 91.6666666667%;\n}\n\n.col-xs-push-12 {\n  left: 100%;\n}\n\n.col-xs-offset-0 {\n  margin-left: 0%;\n}\n\n.col-xs-offset-1 {\n  margin-left: 8.3333333333%;\n}\n\n.col-xs-offset-2 {\n  margin-left: 16.6666666667%;\n}\n\n.col-xs-offset-3 {\n  margin-left: 25%;\n}\n\n.col-xs-offset-4 {\n  margin-left: 33.3333333333%;\n}\n\n.col-xs-offset-5 {\n  margin-left: 41.6666666667%;\n}\n\n.col-xs-offset-6 {\n  margin-left: 50%;\n}\n\n.col-xs-offset-7 {\n  margin-left: 58.3333333333%;\n}\n\n.col-xs-offset-8 {\n  margin-left: 66.6666666667%;\n}\n\n.col-xs-offset-9 {\n  margin-left: 75%;\n}\n\n.col-xs-offset-10 {\n  margin-left: 83.3333333333%;\n}\n\n.col-xs-offset-11 {\n  margin-left: 91.6666666667%;\n}\n\n.col-xs-offset-12 {\n  margin-left: 100%;\n}\n\n@media (min-width: 768px) {\n  .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 {\n    float: left;\n  }\n\n  .col-sm-1 {\n    width: 8.3333333333%;\n  }\n\n  .col-sm-2 {\n    width: 16.6666666667%;\n  }\n\n  .col-sm-3 {\n    width: 25%;\n  }\n\n  .col-sm-4 {\n    width: 33.3333333333%;\n  }\n\n  .col-sm-5 {\n    width: 41.6666666667%;\n  }\n\n  .col-sm-6 {\n    width: 50%;\n  }\n\n  .col-sm-7 {\n    width: 58.3333333333%;\n  }\n\n  .col-sm-8 {\n    width: 66.6666666667%;\n  }\n\n  .col-sm-9 {\n    width: 75%;\n  }\n\n  .col-sm-10 {\n    width: 83.3333333333%;\n  }\n\n  .col-sm-11 {\n    width: 91.6666666667%;\n  }\n\n  .col-sm-12 {\n    width: 100%;\n  }\n\n  .col-sm-pull-0 {\n    right: auto;\n  }\n\n  .col-sm-pull-1 {\n    right: 8.3333333333%;\n  }\n\n  .col-sm-pull-2 {\n    right: 16.6666666667%;\n  }\n\n  .col-sm-pull-3 {\n    right: 25%;\n  }\n\n  .col-sm-pull-4 {\n    right: 33.3333333333%;\n  }\n\n  .col-sm-pull-5 {\n    right: 41.6666666667%;\n  }\n\n  .col-sm-pull-6 {\n    right: 50%;\n  }\n\n  .col-sm-pull-7 {\n    right: 58.3333333333%;\n  }\n\n  .col-sm-pull-8 {\n    right: 66.6666666667%;\n  }\n\n  .col-sm-pull-9 {\n    right: 75%;\n  }\n\n  .col-sm-pull-10 {\n    right: 83.3333333333%;\n  }\n\n  .col-sm-pull-11 {\n    right: 91.6666666667%;\n  }\n\n  .col-sm-pull-12 {\n    right: 100%;\n  }\n\n  .col-sm-push-0 {\n    left: auto;\n  }\n\n  .col-sm-push-1 {\n    left: 8.3333333333%;\n  }\n\n  .col-sm-push-2 {\n    left: 16.6666666667%;\n  }\n\n  .col-sm-push-3 {\n    left: 25%;\n  }\n\n  .col-sm-push-4 {\n    left: 33.3333333333%;\n  }\n\n  .col-sm-push-5 {\n    left: 41.6666666667%;\n  }\n\n  .col-sm-push-6 {\n    left: 50%;\n  }\n\n  .col-sm-push-7 {\n    left: 58.3333333333%;\n  }\n\n  .col-sm-push-8 {\n    left: 66.6666666667%;\n  }\n\n  .col-sm-push-9 {\n    left: 75%;\n  }\n\n  .col-sm-push-10 {\n    left: 83.3333333333%;\n  }\n\n  .col-sm-push-11 {\n    left: 91.6666666667%;\n  }\n\n  .col-sm-push-12 {\n    left: 100%;\n  }\n\n  .col-sm-offset-0 {\n    margin-left: 0%;\n  }\n\n  .col-sm-offset-1 {\n    margin-left: 8.3333333333%;\n  }\n\n  .col-sm-offset-2 {\n    margin-left: 16.6666666667%;\n  }\n\n  .col-sm-offset-3 {\n    margin-left: 25%;\n  }\n\n  .col-sm-offset-4 {\n    margin-left: 33.3333333333%;\n  }\n\n  .col-sm-offset-5 {\n    margin-left: 41.6666666667%;\n  }\n\n  .col-sm-offset-6 {\n    margin-left: 50%;\n  }\n\n  .col-sm-offset-7 {\n    margin-left: 58.3333333333%;\n  }\n\n  .col-sm-offset-8 {\n    margin-left: 66.6666666667%;\n  }\n\n  .col-sm-offset-9 {\n    margin-left: 75%;\n  }\n\n  .col-sm-offset-10 {\n    margin-left: 83.3333333333%;\n  }\n\n  .col-sm-offset-11 {\n    margin-left: 91.6666666667%;\n  }\n\n  .col-sm-offset-12 {\n    margin-left: 100%;\n  }\n}\n@media (min-width: 992px) {\n  .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 {\n    float: left;\n  }\n\n  .col-md-1 {\n    width: 8.3333333333%;\n  }\n\n  .col-md-2 {\n    width: 16.6666666667%;\n  }\n\n  .col-md-3 {\n    width: 25%;\n  }\n\n  .col-md-4 {\n    width: 33.3333333333%;\n  }\n\n  .col-md-5 {\n    width: 41.6666666667%;\n  }\n\n  .col-md-6 {\n    width: 50%;\n  }\n\n  .col-md-7 {\n    width: 58.3333333333%;\n  }\n\n  .col-md-8 {\n    width: 66.6666666667%;\n  }\n\n  .col-md-9 {\n    width: 75%;\n  }\n\n  .col-md-10 {\n    width: 83.3333333333%;\n  }\n\n  .col-md-11 {\n    width: 91.6666666667%;\n  }\n\n  .col-md-12 {\n    width: 100%;\n  }\n\n  .col-md-pull-0 {\n    right: auto;\n  }\n\n  .col-md-pull-1 {\n    right: 8.3333333333%;\n  }\n\n  .col-md-pull-2 {\n    right: 16.6666666667%;\n  }\n\n  .col-md-pull-3 {\n    right: 25%;\n  }\n\n  .col-md-pull-4 {\n    right: 33.3333333333%;\n  }\n\n  .col-md-pull-5 {\n    right: 41.6666666667%;\n  }\n\n  .col-md-pull-6 {\n    right: 50%;\n  }\n\n  .col-md-pull-7 {\n    right: 58.3333333333%;\n  }\n\n  .col-md-pull-8 {\n    right: 66.6666666667%;\n  }\n\n  .col-md-pull-9 {\n    right: 75%;\n  }\n\n  .col-md-pull-10 {\n    right: 83.3333333333%;\n  }\n\n  .col-md-pull-11 {\n    right: 91.6666666667%;\n  }\n\n  .col-md-pull-12 {\n    right: 100%;\n  }\n\n  .col-md-push-0 {\n    left: auto;\n  }\n\n  .col-md-push-1 {\n    left: 8.3333333333%;\n  }\n\n  .col-md-push-2 {\n    left: 16.6666666667%;\n  }\n\n  .col-md-push-3 {\n    left: 25%;\n  }\n\n  .col-md-push-4 {\n    left: 33.3333333333%;\n  }\n\n  .col-md-push-5 {\n    left: 41.6666666667%;\n  }\n\n  .col-md-push-6 {\n    left: 50%;\n  }\n\n  .col-md-push-7 {\n    left: 58.3333333333%;\n  }\n\n  .col-md-push-8 {\n    left: 66.6666666667%;\n  }\n\n  .col-md-push-9 {\n    left: 75%;\n  }\n\n  .col-md-push-10 {\n    left: 83.3333333333%;\n  }\n\n  .col-md-push-11 {\n    left: 91.6666666667%;\n  }\n\n  .col-md-push-12 {\n    left: 100%;\n  }\n\n  .col-md-offset-0 {\n    margin-left: 0%;\n  }\n\n  .col-md-offset-1 {\n    margin-left: 8.3333333333%;\n  }\n\n  .col-md-offset-2 {\n    margin-left: 16.6666666667%;\n  }\n\n  .col-md-offset-3 {\n    margin-left: 25%;\n  }\n\n  .col-md-offset-4 {\n    margin-left: 33.3333333333%;\n  }\n\n  .col-md-offset-5 {\n    margin-left: 41.6666666667%;\n  }\n\n  .col-md-offset-6 {\n    margin-left: 50%;\n  }\n\n  .col-md-offset-7 {\n    margin-left: 58.3333333333%;\n  }\n\n  .col-md-offset-8 {\n    margin-left: 66.6666666667%;\n  }\n\n  .col-md-offset-9 {\n    margin-left: 75%;\n  }\n\n  .col-md-offset-10 {\n    margin-left: 83.3333333333%;\n  }\n\n  .col-md-offset-11 {\n    margin-left: 91.6666666667%;\n  }\n\n  .col-md-offset-12 {\n    margin-left: 100%;\n  }\n}\n@media (min-width: 1200px) {\n  .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 {\n    float: left;\n  }\n\n  .col-lg-1 {\n    width: 8.3333333333%;\n  }\n\n  .col-lg-2 {\n    width: 16.6666666667%;\n  }\n\n  .col-lg-3 {\n    width: 25%;\n  }\n\n  .col-lg-4 {\n    width: 33.3333333333%;\n  }\n\n  .col-lg-5 {\n    width: 41.6666666667%;\n  }\n\n  .col-lg-6 {\n    width: 50%;\n  }\n\n  .col-lg-7 {\n    width: 58.3333333333%;\n  }\n\n  .col-lg-8 {\n    width: 66.6666666667%;\n  }\n\n  .col-lg-9 {\n    width: 75%;\n  }\n\n  .col-lg-10 {\n    width: 83.3333333333%;\n  }\n\n  .col-lg-11 {\n    width: 91.6666666667%;\n  }\n\n  .col-lg-12 {\n    width: 100%;\n  }\n\n  .col-lg-pull-0 {\n    right: auto;\n  }\n\n  .col-lg-pull-1 {\n    right: 8.3333333333%;\n  }\n\n  .col-lg-pull-2 {\n    right: 16.6666666667%;\n  }\n\n  .col-lg-pull-3 {\n    right: 25%;\n  }\n\n  .col-lg-pull-4 {\n    right: 33.3333333333%;\n  }\n\n  .col-lg-pull-5 {\n    right: 41.6666666667%;\n  }\n\n  .col-lg-pull-6 {\n    right: 50%;\n  }\n\n  .col-lg-pull-7 {\n    right: 58.3333333333%;\n  }\n\n  .col-lg-pull-8 {\n    right: 66.6666666667%;\n  }\n\n  .col-lg-pull-9 {\n    right: 75%;\n  }\n\n  .col-lg-pull-10 {\n    right: 83.3333333333%;\n  }\n\n  .col-lg-pull-11 {\n    right: 91.6666666667%;\n  }\n\n  .col-lg-pull-12 {\n    right: 100%;\n  }\n\n  .col-lg-push-0 {\n    left: auto;\n  }\n\n  .col-lg-push-1 {\n    left: 8.3333333333%;\n  }\n\n  .col-lg-push-2 {\n    left: 16.6666666667%;\n  }\n\n  .col-lg-push-3 {\n    left: 25%;\n  }\n\n  .col-lg-push-4 {\n    left: 33.3333333333%;\n  }\n\n  .col-lg-push-5 {\n    left: 41.6666666667%;\n  }\n\n  .col-lg-push-6 {\n    left: 50%;\n  }\n\n  .col-lg-push-7 {\n    left: 58.3333333333%;\n  }\n\n  .col-lg-push-8 {\n    left: 66.6666666667%;\n  }\n\n  .col-lg-push-9 {\n    left: 75%;\n  }\n\n  .col-lg-push-10 {\n    left: 83.3333333333%;\n  }\n\n  .col-lg-push-11 {\n    left: 91.6666666667%;\n  }\n\n  .col-lg-push-12 {\n    left: 100%;\n  }\n\n  .col-lg-offset-0 {\n    margin-left: 0%;\n  }\n\n  .col-lg-offset-1 {\n    margin-left: 8.3333333333%;\n  }\n\n  .col-lg-offset-2 {\n    margin-left: 16.6666666667%;\n  }\n\n  .col-lg-offset-3 {\n    margin-left: 25%;\n  }\n\n  .col-lg-offset-4 {\n    margin-left: 33.3333333333%;\n  }\n\n  .col-lg-offset-5 {\n    margin-left: 41.6666666667%;\n  }\n\n  .col-lg-offset-6 {\n    margin-left: 50%;\n  }\n\n  .col-lg-offset-7 {\n    margin-left: 58.3333333333%;\n  }\n\n  .col-lg-offset-8 {\n    margin-left: 66.6666666667%;\n  }\n\n  .col-lg-offset-9 {\n    margin-left: 75%;\n  }\n\n  .col-lg-offset-10 {\n    margin-left: 83.3333333333%;\n  }\n\n  .col-lg-offset-11 {\n    margin-left: 91.6666666667%;\n  }\n\n  .col-lg-offset-12 {\n    margin-left: 100%;\n  }\n}\ntable {\n  background-color: transparent;\n}\n\nth {\n  text-align: left;\n}\n\n.table {\n  width: 100%;\n  max-width: 100%;\n  margin-bottom: 20px;\n}\n.table > thead > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > th,\n.table > tbody > tr > td,\n.table > tfoot > tr > th,\n.table > tfoot > tr > td {\n  padding: 8px;\n  line-height: 1.428571429;\n  vertical-align: top;\n  border-top: 1px solid #ddd;\n}\n.table > thead > tr > th {\n  vertical-align: bottom;\n  border-bottom: 2px solid #ddd;\n}\n.table > caption + thead > tr:first-child > th,\n.table > caption + thead > tr:first-child > td,\n.table > colgroup + thead > tr:first-child > th,\n.table > colgroup + thead > tr:first-child > td,\n.table > thead:first-child > tr:first-child > th,\n.table > thead:first-child > tr:first-child > td {\n  border-top: 0;\n}\n.table > tbody + tbody {\n  border-top: 2px solid #ddd;\n}\n.table .table {\n  background-color: #fff;\n}\n\n.table-condensed > thead > tr > th,\n.table-condensed > thead > tr > td,\n.table-condensed > tbody > tr > th,\n.table-condensed > tbody > tr > td,\n.table-condensed > tfoot > tr > th,\n.table-condensed > tfoot > tr > td {\n  padding: 5px;\n}\n\n.table-bordered {\n  border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > th,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > th,\n.table-bordered > tfoot > tr > td {\n  border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n  border-bottom-width: 2px;\n}\n\n.table-striped > tbody > tr:nth-child(odd) > td,\n.table-striped > tbody > tr:nth-child(odd) > th {\n  background-color: #f9f9f9;\n}\n\n.table-hover > tbody > tr:hover > td,\n.table-hover > tbody > tr:hover > th {\n  background-color: #f5f5f5;\n}\n\ntable col[class*=\"col-\"] {\n  position: static;\n  float: none;\n  display: table-column;\n}\n\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n  position: static;\n  float: none;\n  display: table-cell;\n}\n\n.table > thead > tr > td.active,\n.table > thead > tr > th.active, .table > thead > tr.active > td, .table > thead > tr.active > th,\n.table > tbody > tr > td.active,\n.table > tbody > tr > th.active,\n.table > tbody > tr.active > td,\n.table > tbody > tr.active > th,\n.table > tfoot > tr > td.active,\n.table > tfoot > tr > th.active,\n.table > tfoot > tr.active > td,\n.table > tfoot > tr.active > th {\n  background-color: #f5f5f5;\n}\n\n.table-hover > tbody > tr > td.active:hover,\n.table-hover > tbody > tr > th.active:hover, .table-hover > tbody > tr.active:hover > td, .table-hover > tbody > tr:hover > .active, .table-hover > tbody > tr.active:hover > th {\n  background-color: #e8e8e8;\n}\n\n.table > thead > tr > td.success,\n.table > thead > tr > th.success, .table > thead > tr.success > td, .table > thead > tr.success > th,\n.table > tbody > tr > td.success,\n.table > tbody > tr > th.success,\n.table > tbody > tr.success > td,\n.table > tbody > tr.success > th,\n.table > tfoot > tr > td.success,\n.table > tfoot > tr > th.success,\n.table > tfoot > tr.success > td,\n.table > tfoot > tr.success > th {\n  background-color: #dff0d8;\n}\n\n.table-hover > tbody > tr > td.success:hover,\n.table-hover > tbody > tr > th.success:hover, .table-hover > tbody > tr.success:hover > td, .table-hover > tbody > tr:hover > .success, .table-hover > tbody > tr.success:hover > th {\n  background-color: #d0e9c6;\n}\n\n.table > thead > tr > td.info,\n.table > thead > tr > th.info, .table > thead > tr.info > td, .table > thead > tr.info > th,\n.table > tbody > tr > td.info,\n.table > tbody > tr > th.info,\n.table > tbody > tr.info > td,\n.table > tbody > tr.info > th,\n.table > tfoot > tr > td.info,\n.table > tfoot > tr > th.info,\n.table > tfoot > tr.info > td,\n.table > tfoot > tr.info > th {\n  background-color: #d9edf7;\n}\n\n.table-hover > tbody > tr > td.info:hover,\n.table-hover > tbody > tr > th.info:hover, .table-hover > tbody > tr.info:hover > td, .table-hover > tbody > tr:hover > .info, .table-hover > tbody > tr.info:hover > th {\n  background-color: #c4e3f3;\n}\n\n.table > thead > tr > td.warning,\n.table > thead > tr > th.warning, .table > thead > tr.warning > td, .table > thead > tr.warning > th,\n.table > tbody > tr > td.warning,\n.table > tbody > tr > th.warning,\n.table > tbody > tr.warning > td,\n.table > tbody > tr.warning > th,\n.table > tfoot > tr > td.warning,\n.table > tfoot > tr > th.warning,\n.table > tfoot > tr.warning > td,\n.table > tfoot > tr.warning > th {\n  background-color: #fcf8e3;\n}\n\n.table-hover > tbody > tr > td.warning:hover,\n.table-hover > tbody > tr > th.warning:hover, .table-hover > tbody > tr.warning:hover > td, .table-hover > tbody > tr:hover > .warning, .table-hover > tbody > tr.warning:hover > th {\n  background-color: #faf2cc;\n}\n\n.table > thead > tr > td.danger,\n.table > thead > tr > th.danger, .table > thead > tr.danger > td, .table > thead > tr.danger > th,\n.table > tbody > tr > td.danger,\n.table > tbody > tr > th.danger,\n.table > tbody > tr.danger > td,\n.table > tbody > tr.danger > th,\n.table > tfoot > tr > td.danger,\n.table > tfoot > tr > th.danger,\n.table > tfoot > tr.danger > td,\n.table > tfoot > tr.danger > th {\n  background-color: #f2dede;\n}\n\n.table-hover > tbody > tr > td.danger:hover,\n.table-hover > tbody > tr > th.danger:hover, .table-hover > tbody > tr.danger:hover > td, .table-hover > tbody > tr:hover > .danger, .table-hover > tbody > tr.danger:hover > th {\n  background-color: #ebcccc;\n}\n\n@media screen and (max-width: 767px) {\n  .table-responsive {\n    width: 100%;\n    margin-bottom: 15px;\n    overflow-y: hidden;\n    overflow-x: auto;\n    -ms-overflow-style: -ms-autohiding-scrollbar;\n    border: 1px solid #ddd;\n    -webkit-overflow-scrolling: touch;\n  }\n  .table-responsive > .table {\n    margin-bottom: 0;\n  }\n  .table-responsive > .table > thead > tr > th,\n  .table-responsive > .table > thead > tr > td,\n  .table-responsive > .table > tbody > tr > th,\n  .table-responsive > .table > tbody > tr > td,\n  .table-responsive > .table > tfoot > tr > th,\n  .table-responsive > .table > tfoot > tr > td {\n    white-space: nowrap;\n  }\n  .table-responsive > .table-bordered {\n    border: 0;\n  }\n  .table-responsive > .table-bordered > thead > tr > th:first-child,\n  .table-responsive > .table-bordered > thead > tr > td:first-child,\n  .table-responsive > .table-bordered > tbody > tr > th:first-child,\n  .table-responsive > .table-bordered > tbody > tr > td:first-child,\n  .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n  .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n    border-left: 0;\n  }\n  .table-responsive > .table-bordered > thead > tr > th:last-child,\n  .table-responsive > .table-bordered > thead > tr > td:last-child,\n  .table-responsive > .table-bordered > tbody > tr > th:last-child,\n  .table-responsive > .table-bordered > tbody > tr > td:last-child,\n  .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n  .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n    border-right: 0;\n  }\n  .table-responsive > .table-bordered > tbody > tr:last-child > th,\n  .table-responsive > .table-bordered > tbody > tr:last-child > td,\n  .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n  .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n    border-bottom: 0;\n  }\n}\n\nfieldset {\n  padding: 0;\n  margin: 0;\n  border: 0;\n  min-width: 0;\n}\n\nlegend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: 20px;\n  font-size: 21px;\n  line-height: inherit;\n  color: #333333;\n  border: 0;\n  border-bottom: 1px solid #e5e5e5;\n}\n\nlabel {\n  display: inline-block;\n  max-width: 100%;\n  margin-bottom: 5px;\n  font-weight: bold;\n}\n\ninput[type=\"search\"] {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  margin: 4px 0 0;\n  margin-top: 1px \\9;\n  line-height: normal;\n}\n\ninput[type=\"file\"] {\n  display: block;\n}\n\ninput[type=\"range\"] {\n  display: block;\n  width: 100%;\n}\n\nselect[multiple],\nselect[size] {\n  height: auto;\n}\n\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n\noutput {\n  display: block;\n  padding-top: 7px;\n  font-size: 14px;\n  line-height: 1.428571429;\n  color: #555555;\n}\n\n.form-control {\n  display: block;\n  width: 100%;\n  height: 34px;\n  padding: 6px 12px;\n  font-size: 14px;\n  line-height: 1.428571429;\n  color: #555555;\n  background-color: #fff;\n  background-image: none;\n  border: 1px solid #ccc;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  -webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;\n  -o-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;\n  transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;\n}\n.form-control:focus {\n  border-color: #66afe9;\n  outline: 0;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);\n}\n.form-control::-moz-placeholder {\n  color: #777777;\n  opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n  color: #777777;\n}\n.form-control::-webkit-input-placeholder {\n  color: #777777;\n}\n.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control {\n  cursor: not-allowed;\n  background-color: #eeeeee;\n  opacity: 1;\n}\n\ntextarea.form-control {\n  height: auto;\n}\n\ninput[type=\"search\"] {\n  -webkit-appearance: none;\n}\n\ninput[type=\"date\"],\ninput[type=\"time\"],\ninput[type=\"datetime-local\"],\ninput[type=\"month\"] {\n  line-height: 34px;\n  line-height: 1.428571429 \\0;\n}\ninput[type=\"date\"].input-sm, .form-horizontal .form-group-sm input[type=\"date\"].form-control, .input-group-sm > input[type=\"date\"].form-control,\n.input-group-sm > input[type=\"date\"].input-group-addon,\n.input-group-sm > .input-group-btn > input[type=\"date\"].btn,\ninput[type=\"time\"].input-sm,\n.form-horizontal .form-group-sm input[type=\"time\"].form-control,\n.input-group-sm > input[type=\"time\"].form-control,\n.input-group-sm > input[type=\"time\"].input-group-addon,\n.input-group-sm > .input-group-btn > input[type=\"time\"].btn,\ninput[type=\"datetime-local\"].input-sm,\n.form-horizontal .form-group-sm input[type=\"datetime-local\"].form-control,\n.input-group-sm > input[type=\"datetime-local\"].form-control,\n.input-group-sm > input[type=\"datetime-local\"].input-group-addon,\n.input-group-sm > .input-group-btn > input[type=\"datetime-local\"].btn,\ninput[type=\"month\"].input-sm,\n.form-horizontal .form-group-sm input[type=\"month\"].form-control,\n.input-group-sm > input[type=\"month\"].form-control,\n.input-group-sm > input[type=\"month\"].input-group-addon,\n.input-group-sm > .input-group-btn > input[type=\"month\"].btn {\n  line-height: 30px;\n}\ninput[type=\"date\"].input-lg, .form-horizontal .form-group-lg input[type=\"date\"].form-control, .input-group-lg > input[type=\"date\"].form-control,\n.input-group-lg > input[type=\"date\"].input-group-addon,\n.input-group-lg > .input-group-btn > input[type=\"date\"].btn,\ninput[type=\"time\"].input-lg,\n.form-horizontal .form-group-lg input[type=\"time\"].form-control,\n.input-group-lg > input[type=\"time\"].form-control,\n.input-group-lg > input[type=\"time\"].input-group-addon,\n.input-group-lg > .input-group-btn > input[type=\"time\"].btn,\ninput[type=\"datetime-local\"].input-lg,\n.form-horizontal .form-group-lg input[type=\"datetime-local\"].form-control,\n.input-group-lg > input[type=\"datetime-local\"].form-control,\n.input-group-lg > input[type=\"datetime-local\"].input-group-addon,\n.input-group-lg > .input-group-btn > input[type=\"datetime-local\"].btn,\ninput[type=\"month\"].input-lg,\n.form-horizontal .form-group-lg input[type=\"month\"].form-control,\n.input-group-lg > input[type=\"month\"].form-control,\n.input-group-lg > input[type=\"month\"].input-group-addon,\n.input-group-lg > .input-group-btn > input[type=\"month\"].btn {\n  line-height: 46px;\n}\n\n.form-group {\n  margin-bottom: 15px;\n}\n\n.radio,\n.checkbox {\n  position: relative;\n  display: block;\n  min-height: 20px;\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n.radio label,\n.checkbox label {\n  padding-left: 20px;\n  margin-bottom: 0;\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  position: absolute;\n  margin-left: -20px;\n  margin-top: 4px \\9;\n}\n\n.radio + .radio,\n.checkbox + .checkbox {\n  margin-top: -5px;\n}\n\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\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n  margin-top: 0;\n  margin-left: 10px;\n}\n\ninput[type=\"radio\"][disabled], input[type=\"radio\"].disabled, fieldset[disabled] input[type=\"radio\"],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"checkbox\"].disabled, fieldset[disabled]\ninput[type=\"checkbox\"] {\n  cursor: not-allowed;\n}\n\n.radio-inline.disabled, fieldset[disabled] .radio-inline,\n.checkbox-inline.disabled, fieldset[disabled]\n.checkbox-inline {\n  cursor: not-allowed;\n}\n\n.radio.disabled label, fieldset[disabled] .radio label,\n.checkbox.disabled label, fieldset[disabled]\n.checkbox label {\n  cursor: not-allowed;\n}\n\n.form-control-static {\n  padding-top: 7px;\n  padding-bottom: 7px;\n  margin-bottom: 0;\n}\n.form-control-static.input-lg, .form-horizontal .form-group-lg .form-control-static.form-control, .input-group-lg > .form-control-static.form-control,\n.input-group-lg > .form-control-static.input-group-addon,\n.input-group-lg > .input-group-btn > .form-control-static.btn, .form-control-static.input-sm, .form-horizontal .form-group-sm .form-control-static.form-control, .input-group-sm > .form-control-static.form-control,\n.input-group-sm > .form-control-static.input-group-addon,\n.input-group-sm > .input-group-btn > .form-control-static.btn {\n  padding-left: 0;\n  padding-right: 0;\n}\n\n.input-sm, .form-horizontal .form-group-sm .form-control, .input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n\nselect.input-sm, .form-horizontal .form-group-sm select.form-control, .input-group-sm > select.form-control,\n.input-group-sm > select.input-group-addon,\n.input-group-sm > .input-group-btn > select.btn {\n  height: 30px;\n  line-height: 30px;\n}\n\ntextarea.input-sm, .form-horizontal .form-group-sm textarea.form-control, .input-group-sm > textarea.form-control,\n.input-group-sm > textarea.input-group-addon,\n.input-group-sm > .input-group-btn > textarea.btn,\nselect[multiple].input-sm,\n.form-horizontal .form-group-sm select[multiple].form-control,\n.input-group-sm > select[multiple].form-control,\n.input-group-sm > select[multiple].input-group-addon,\n.input-group-sm > .input-group-btn > select[multiple].btn {\n  height: auto;\n}\n\n.input-lg, .form-horizontal .form-group-lg .form-control, .input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n  height: 46px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.33;\n  border-radius: 6px;\n}\n\nselect.input-lg, .form-horizontal .form-group-lg select.form-control, .input-group-lg > select.form-control,\n.input-group-lg > select.input-group-addon,\n.input-group-lg > .input-group-btn > select.btn {\n  height: 46px;\n  line-height: 46px;\n}\n\ntextarea.input-lg, .form-horizontal .form-group-lg textarea.form-control, .input-group-lg > textarea.form-control,\n.input-group-lg > textarea.input-group-addon,\n.input-group-lg > .input-group-btn > textarea.btn,\nselect[multiple].input-lg,\n.form-horizontal .form-group-lg select[multiple].form-control,\n.input-group-lg > select[multiple].form-control,\n.input-group-lg > select[multiple].input-group-addon,\n.input-group-lg > .input-group-btn > select[multiple].btn {\n  height: auto;\n}\n\n.has-feedback {\n  position: relative;\n}\n.has-feedback .form-control {\n  padding-right: 42.5px;\n}\n\n.form-control-feedback {\n  position: absolute;\n  top: 25px;\n  right: 0;\n  z-index: 2;\n  display: block;\n  width: 34px;\n  height: 34px;\n  line-height: 34px;\n  text-align: center;\n}\n\n.input-lg + .form-control-feedback, .form-horizontal .form-group-lg .form-control + .form-control-feedback, .input-group-lg > .form-control + .form-control-feedback,\n.input-group-lg > .input-group-addon + .form-control-feedback,\n.input-group-lg > .input-group-btn > .btn + .form-control-feedback {\n  width: 46px;\n  height: 46px;\n  line-height: 46px;\n}\n\n.input-sm + .form-control-feedback, .form-horizontal .form-group-sm .form-control + .form-control-feedback, .input-group-sm > .form-control + .form-control-feedback,\n.input-group-sm > .input-group-addon + .form-control-feedback,\n.input-group-sm > .input-group-btn > .btn + .form-control-feedback {\n  width: 30px;\n  height: 30px;\n  line-height: 30px;\n}\n\n.has-success .help-block,\n.has-success .control-label,\n.has-success .radio,\n.has-success .checkbox,\n.has-success .radio-inline,\n.has-success .checkbox-inline {\n  color: #3c763d;\n}\n.has-success .form-control {\n  border-color: #3c763d;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-success .form-control:focus {\n  border-color: #2b542c;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n}\n.has-success .input-group-addon {\n  color: #3c763d;\n  border-color: #3c763d;\n  background-color: #dff0d8;\n}\n.has-success .form-control-feedback {\n  color: #3c763d;\n}\n\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .radio,\n.has-warning .checkbox,\n.has-warning .radio-inline,\n.has-warning .checkbox-inline {\n  color: #8a6d3b;\n}\n.has-warning .form-control {\n  border-color: #8a6d3b;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-warning .form-control:focus {\n  border-color: #66512c;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n}\n.has-warning .input-group-addon {\n  color: #8a6d3b;\n  border-color: #8a6d3b;\n  background-color: #fcf8e3;\n}\n.has-warning .form-control-feedback {\n  color: #8a6d3b;\n}\n\n.has-error .help-block,\n.has-error .control-label,\n.has-error .radio,\n.has-error .checkbox,\n.has-error .radio-inline,\n.has-error .checkbox-inline {\n  color: #a94442;\n}\n.has-error .form-control {\n  border-color: #a94442;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-error .form-control:focus {\n  border-color: #843534;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n}\n.has-error .input-group-addon {\n  color: #a94442;\n  border-color: #a94442;\n  background-color: #f2dede;\n}\n.has-error .form-control-feedback {\n  color: #a94442;\n}\n\n.has-feedback label.sr-only ~ .form-control-feedback {\n  top: 0;\n}\n\n.help-block {\n  display: block;\n  margin-top: 5px;\n  margin-bottom: 10px;\n  color: #737373;\n}\n\n@media (min-width: 768px) {\n  .form-inline .form-group, .navbar-form .form-group {\n    display: inline-block;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .form-control, .navbar-form .form-control {\n    display: inline-block;\n    width: auto;\n    vertical-align: middle;\n  }\n  .form-inline .input-group, .navbar-form .input-group {\n    display: inline-table;\n    vertical-align: middle;\n  }\n  .form-inline .input-group .input-group-addon, .navbar-form .input-group .input-group-addon,\n  .form-inline .input-group .input-group-btn,\n  .navbar-form .input-group .input-group-btn,\n  .form-inline .input-group .form-control,\n  .navbar-form .input-group .form-control {\n    width: auto;\n  }\n  .form-inline .input-group > .form-control, .navbar-form .input-group > .form-control {\n    width: 100%;\n  }\n  .form-inline .control-label, .navbar-form .control-label {\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .radio, .navbar-form .radio,\n  .form-inline .checkbox,\n  .navbar-form .checkbox {\n    display: inline-block;\n    margin-top: 0;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .radio label, .navbar-form .radio label,\n  .form-inline .checkbox label,\n  .navbar-form .checkbox label {\n    padding-left: 0;\n  }\n  .form-inline .radio input[type=\"radio\"], .navbar-form .radio input[type=\"radio\"],\n  .form-inline .checkbox input[type=\"checkbox\"],\n  .navbar-form .checkbox input[type=\"checkbox\"] {\n    position: relative;\n    margin-left: 0;\n  }\n  .form-inline .has-feedback .form-control-feedback, .navbar-form .has-feedback .form-control-feedback {\n    top: 0;\n  }\n}\n\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n  margin-top: 0;\n  margin-bottom: 0;\n  padding-top: 7px;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n  min-height: 27px;\n}\n.form-horizontal .form-group {\n  margin-left: -15px;\n  margin-right: -15px;\n}\n.form-horizontal .form-group:before, .form-horizontal .form-group:after {\n  content: \" \";\n  display: table;\n}\n.form-horizontal .form-group:after {\n  clear: both;\n}\n@media (min-width: 768px) {\n  .form-horizontal .control-label {\n    text-align: right;\n    margin-bottom: 0;\n    padding-top: 7px;\n  }\n}\n.form-horizontal .has-feedback .form-control-feedback {\n  top: 0;\n  right: 15px;\n}\n@media (min-width: 768px) {\n  .form-horizontal .form-group-lg .control-label {\n    padding-top: 14.3px;\n  }\n}\n@media (min-width: 768px) {\n  .form-horizontal .form-group-sm .control-label {\n    padding-top: 6px;\n  }\n}\n\n.btn {\n  display: inline-block;\n  margin-bottom: 0;\n  font-weight: normal;\n  text-align: center;\n  vertical-align: middle;\n  cursor: pointer;\n  background-image: none;\n  border: 1px solid transparent;\n  white-space: nowrap;\n  padding: 6px 12px;\n  font-size: 14px;\n  line-height: 1.428571429;\n  border-radius: 4px;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n}\n.btn:focus, .btn:active:focus, .btn.active:focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n.btn:hover, .btn:focus {\n  color: #333;\n  text-decoration: none;\n}\n.btn:active, .btn.active {\n  outline: 0;\n  background-image: none;\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn.disabled, .btn[disabled], fieldset[disabled] .btn {\n  cursor: not-allowed;\n  pointer-events: none;\n  opacity: 0.65;\n  filter: alpha(opacity=65);\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n\n.btn-default {\n  color: #333;\n  background-color: #fff;\n  border-color: #ccc;\n}\n.btn-default:hover, .btn-default:focus, .btn-default:active, .btn-default.active, .open > .btn-default.dropdown-toggle {\n  color: #333;\n  background-color: #e6e6e6;\n  border-color: #adadad;\n}\n.btn-default:active, .btn-default.active, .open > .btn-default.dropdown-toggle {\n  background-image: none;\n}\n.btn-default.disabled, .btn-default.disabled:hover, .btn-default.disabled:focus, .btn-default.disabled:active, .btn-default.disabled.active, .btn-default[disabled], .btn-default[disabled]:hover, .btn-default[disabled]:focus, .btn-default[disabled]:active, .btn-default[disabled].active, fieldset[disabled] .btn-default, fieldset[disabled] .btn-default:hover, fieldset[disabled] .btn-default:focus, fieldset[disabled] .btn-default:active, fieldset[disabled] .btn-default.active {\n  background-color: #fff;\n  border-color: #ccc;\n}\n.btn-default .badge {\n  color: #fff;\n  background-color: #333;\n}\n\n.btn-primary {\n  color: #fff;\n  background-color: #428bca;\n  border-color: #357ebd;\n}\n.btn-primary:hover, .btn-primary:focus, .btn-primary:active, .btn-primary.active, .open > .btn-primary.dropdown-toggle {\n  color: #fff;\n  background-color: #3071a9;\n  border-color: #285e8e;\n}\n.btn-primary:active, .btn-primary.active, .open > .btn-primary.dropdown-toggle {\n  background-image: none;\n}\n.btn-primary.disabled, .btn-primary.disabled:hover, .btn-primary.disabled:focus, .btn-primary.disabled:active, .btn-primary.disabled.active, .btn-primary[disabled], .btn-primary[disabled]:hover, .btn-primary[disabled]:focus, .btn-primary[disabled]:active, .btn-primary[disabled].active, fieldset[disabled] .btn-primary, fieldset[disabled] .btn-primary:hover, fieldset[disabled] .btn-primary:focus, fieldset[disabled] .btn-primary:active, fieldset[disabled] .btn-primary.active {\n  background-color: #428bca;\n  border-color: #357ebd;\n}\n.btn-primary .badge {\n  color: #428bca;\n  background-color: #fff;\n}\n\n.btn-success {\n  color: #fff;\n  background-color: #5cb85c;\n  border-color: #4cae4c;\n}\n.btn-success:hover, .btn-success:focus, .btn-success:active, .btn-success.active, .open > .btn-success.dropdown-toggle {\n  color: #fff;\n  background-color: #449d44;\n  border-color: #398439;\n}\n.btn-success:active, .btn-success.active, .open > .btn-success.dropdown-toggle {\n  background-image: none;\n}\n.btn-success.disabled, .btn-success.disabled:hover, .btn-success.disabled:focus, .btn-success.disabled:active, .btn-success.disabled.active, .btn-success[disabled], .btn-success[disabled]:hover, .btn-success[disabled]:focus, .btn-success[disabled]:active, .btn-success[disabled].active, fieldset[disabled] .btn-success, fieldset[disabled] .btn-success:hover, fieldset[disabled] .btn-success:focus, fieldset[disabled] .btn-success:active, fieldset[disabled] .btn-success.active {\n  background-color: #5cb85c;\n  border-color: #4cae4c;\n}\n.btn-success .badge {\n  color: #5cb85c;\n  background-color: #fff;\n}\n\n.btn-info {\n  color: #fff;\n  background-color: #5bc0de;\n  border-color: #46b8da;\n}\n.btn-info:hover, .btn-info:focus, .btn-info:active, .btn-info.active, .open > .btn-info.dropdown-toggle {\n  color: #fff;\n  background-color: #31b0d5;\n  border-color: #269abc;\n}\n.btn-info:active, .btn-info.active, .open > .btn-info.dropdown-toggle {\n  background-image: none;\n}\n.btn-info.disabled, .btn-info.disabled:hover, .btn-info.disabled:focus, .btn-info.disabled:active, .btn-info.disabled.active, .btn-info[disabled], .btn-info[disabled]:hover, .btn-info[disabled]:focus, .btn-info[disabled]:active, .btn-info[disabled].active, fieldset[disabled] .btn-info, fieldset[disabled] .btn-info:hover, fieldset[disabled] .btn-info:focus, fieldset[disabled] .btn-info:active, fieldset[disabled] .btn-info.active {\n  background-color: #5bc0de;\n  border-color: #46b8da;\n}\n.btn-info .badge {\n  color: #5bc0de;\n  background-color: #fff;\n}\n\n.btn-warning {\n  color: #fff;\n  background-color: #f0ad4e;\n  border-color: #eea236;\n}\n.btn-warning:hover, .btn-warning:focus, .btn-warning:active, .btn-warning.active, .open > .btn-warning.dropdown-toggle {\n  color: #fff;\n  background-color: #ec971f;\n  border-color: #d58512;\n}\n.btn-warning:active, .btn-warning.active, .open > .btn-warning.dropdown-toggle {\n  background-image: none;\n}\n.btn-warning.disabled, .btn-warning.disabled:hover, .btn-warning.disabled:focus, .btn-warning.disabled:active, .btn-warning.disabled.active, .btn-warning[disabled], .btn-warning[disabled]:hover, .btn-warning[disabled]:focus, .btn-warning[disabled]:active, .btn-warning[disabled].active, fieldset[disabled] .btn-warning, fieldset[disabled] .btn-warning:hover, fieldset[disabled] .btn-warning:focus, fieldset[disabled] .btn-warning:active, fieldset[disabled] .btn-warning.active {\n  background-color: #f0ad4e;\n  border-color: #eea236;\n}\n.btn-warning .badge {\n  color: #f0ad4e;\n  background-color: #fff;\n}\n\n.btn-danger {\n  color: #fff;\n  background-color: #d9534f;\n  border-color: #d43f3a;\n}\n.btn-danger:hover, .btn-danger:focus, .btn-danger:active, .btn-danger.active, .open > .btn-danger.dropdown-toggle {\n  color: #fff;\n  background-color: #c9302c;\n  border-color: #ac2925;\n}\n.btn-danger:active, .btn-danger.active, .open > .btn-danger.dropdown-toggle {\n  background-image: none;\n}\n.btn-danger.disabled, .btn-danger.disabled:hover, .btn-danger.disabled:focus, .btn-danger.disabled:active, .btn-danger.disabled.active, .btn-danger[disabled], .btn-danger[disabled]:hover, .btn-danger[disabled]:focus, .btn-danger[disabled]:active, .btn-danger[disabled].active, fieldset[disabled] .btn-danger, fieldset[disabled] .btn-danger:hover, fieldset[disabled] .btn-danger:focus, fieldset[disabled] .btn-danger:active, fieldset[disabled] .btn-danger.active {\n  background-color: #d9534f;\n  border-color: #d43f3a;\n}\n.btn-danger .badge {\n  color: #d9534f;\n  background-color: #fff;\n}\n\n.btn-link {\n  color: #428bca;\n  font-weight: normal;\n  cursor: pointer;\n  border-radius: 0;\n}\n.btn-link, .btn-link:active, .btn-link[disabled], fieldset[disabled] .btn-link {\n  background-color: transparent;\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n.btn-link, .btn-link:hover, .btn-link:focus, .btn-link:active {\n  border-color: transparent;\n}\n.btn-link:hover, .btn-link:focus {\n  color: #2a6496;\n  text-decoration: underline;\n  background-color: transparent;\n}\n.btn-link[disabled]:hover, .btn-link[disabled]:focus, fieldset[disabled] .btn-link:hover, fieldset[disabled] .btn-link:focus {\n  color: #777777;\n  text-decoration: none;\n}\n\n.btn-lg, .btn-group-lg > .btn {\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.33;\n  border-radius: 6px;\n}\n\n.btn-sm, .btn-group-sm > .btn {\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n\n.btn-xs, .btn-group-xs > .btn {\n  padding: 1px 5px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n\n.btn-block {\n  display: block;\n  width: 100%;\n}\n\n.btn-block + .btn-block {\n  margin-top: 5px;\n}\n\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n  width: 100%;\n}\n\n.fade {\n  opacity: 0;\n  -webkit-transition: opacity 0.15s linear;\n  -o-transition: opacity 0.15s linear;\n  transition: opacity 0.15s linear;\n}\n.fade.in {\n  opacity: 1;\n}\n\n.collapse {\n  display: none;\n}\n.collapse.in {\n  display: block;\n}\n\ntr.collapse.in {\n  display: table-row;\n}\n\ntbody.collapse.in {\n  display: table-row-group;\n}\n\n.collapsing {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  -webkit-transition: height 0.35s ease;\n  -o-transition: height 0.35s ease;\n  transition: height 0.35s ease;\n}\n\n.caret {\n  display: inline-block;\n  width: 0;\n  height: 0;\n  margin-left: 2px;\n  vertical-align: middle;\n  border-top: 4px solid;\n  border-right: 4px solid transparent;\n  border-left: 4px solid transparent;\n}\n\n.dropdown {\n  position: relative;\n}\n\n.dropdown-toggle:focus {\n  outline: 0;\n}\n\n.dropdown-menu {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  z-index: 1000;\n  display: none;\n  float: left;\n  min-width: 160px;\n  padding: 5px 0;\n  margin: 2px 0 0;\n  list-style: none;\n  font-size: 14px;\n  text-align: left;\n  background-color: #fff;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, 0.15);\n  border-radius: 4px;\n  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n  background-clip: padding-box;\n}\n.dropdown-menu.pull-right {\n  right: 0;\n  left: auto;\n}\n.dropdown-menu .divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: #e5e5e5;\n}\n.dropdown-menu > li > a {\n  display: block;\n  padding: 3px 20px;\n  clear: both;\n  font-weight: normal;\n  line-height: 1.428571429;\n  color: #333333;\n  white-space: nowrap;\n}\n\n.dropdown-menu > li > a:hover, .dropdown-menu > li > a:focus {\n  text-decoration: none;\n  color: #262626;\n  background-color: #f5f5f5;\n}\n\n.dropdown-menu > .active > a, .dropdown-menu > .active > a:hover, .dropdown-menu > .active > a:focus {\n  color: #fff;\n  text-decoration: none;\n  outline: 0;\n  background-color: #428bca;\n}\n\n.dropdown-menu > .disabled > a, .dropdown-menu > .disabled > a:hover, .dropdown-menu > .disabled > a:focus {\n  color: #777777;\n}\n\n.dropdown-menu > .disabled > a:hover, .dropdown-menu > .disabled > a:focus {\n  text-decoration: none;\n  background-color: transparent;\n  background-image: none;\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  cursor: not-allowed;\n}\n\n.open > .dropdown-menu {\n  display: block;\n}\n.open > a {\n  outline: 0;\n}\n\n.dropdown-menu-right {\n  left: auto;\n  right: 0;\n}\n\n.dropdown-menu-left {\n  left: 0;\n  right: auto;\n}\n\n.dropdown-header {\n  display: block;\n  padding: 3px 20px;\n  font-size: 12px;\n  line-height: 1.428571429;\n  color: #777777;\n  white-space: nowrap;\n}\n\n.dropdown-backdrop {\n  position: fixed;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  top: 0;\n  z-index: 990;\n}\n\n.pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n  border-top: 0;\n  border-bottom: 4px solid;\n  content: \"\";\n}\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n  top: auto;\n  bottom: 100%;\n  margin-bottom: 1px;\n}\n\n@media (min-width: 768px) {\n  .navbar-right .dropdown-menu {\n    right: 0;\n    left: auto;\n  }\n  .navbar-right .dropdown-menu-left {\n    left: 0;\n    right: auto;\n  }\n}\n.btn-group,\n.btn-group-vertical {\n  position: relative;\n  display: inline-block;\n  vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n  position: relative;\n  float: left;\n}\n.btn-group > .btn:hover, .btn-group > .btn:focus, .btn-group > .btn:active, .btn-group > .btn.active,\n.btn-group-vertical > .btn:hover,\n.btn-group-vertical > .btn:focus,\n.btn-group-vertical > .btn:active,\n.btn-group-vertical > .btn.active {\n  z-index: 2;\n}\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus {\n  outline: 0;\n}\n\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group {\n  margin-left: -1px;\n}\n\n.btn-toolbar {\n  margin-left: -5px;\n}\n.btn-toolbar:before, .btn-toolbar:after {\n  content: \" \";\n  display: table;\n}\n.btn-toolbar:after {\n  clear: both;\n}\n.btn-toolbar .btn-group,\n.btn-toolbar .input-group {\n  float: left;\n}\n.btn-toolbar > .btn,\n.btn-toolbar > .btn-group,\n.btn-toolbar > .input-group {\n  margin-left: 5px;\n}\n\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n  border-radius: 0;\n}\n\n.btn-group > .btn:first-child {\n  margin-left: 0;\n}\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n  border-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n  border-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n}\n\n.btn-group > .btn-group {\n  float: left;\n}\n\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n\n.btn-group > .btn-group:first-child > .btn:last-child,\n.btn-group > .btn-group:first-child > .dropdown-toggle {\n  border-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n\n.btn-group > .btn-group:last-child > .btn:first-child {\n  border-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n}\n\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n  outline: 0;\n}\n\n.btn-group > .btn + .dropdown-toggle {\n  padding-left: 8px;\n  padding-right: 8px;\n}\n\n.btn-group > .btn-lg + .dropdown-toggle, .btn-group-lg.btn-group > .btn + .dropdown-toggle {\n  padding-left: 12px;\n  padding-right: 12px;\n}\n\n.btn-group.open .dropdown-toggle {\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-group.open .dropdown-toggle.btn-link {\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n\n.btn .caret {\n  margin-left: 0;\n}\n\n.btn-lg .caret, .btn-group-lg > .btn .caret {\n  border-width: 5px 5px 0;\n  border-bottom-width: 0;\n}\n\n.dropup .btn-lg .caret, .dropup .btn-group-lg > .btn .caret {\n  border-width: 0 5px 5px;\n}\n\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group,\n.btn-group-vertical > .btn-group > .btn {\n  display: block;\n  float: none;\n  width: 100%;\n  max-width: 100%;\n}\n.btn-group-vertical > .btn-group:before, .btn-group-vertical > .btn-group:after {\n  content: \" \";\n  display: table;\n}\n.btn-group-vertical > .btn-group:after {\n  clear: both;\n}\n.btn-group-vertical > .btn-group > .btn {\n  float: none;\n}\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n  margin-top: -1px;\n  margin-left: 0;\n}\n\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n  border-top-right-radius: 4px;\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n  border-bottom-left-radius: 4px;\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n\n.btn-group-justified {\n  display: table;\n  width: 100%;\n  table-layout: fixed;\n  border-collapse: separate;\n}\n.btn-group-justified > .btn,\n.btn-group-justified > .btn-group {\n  float: none;\n  display: table-cell;\n  width: 1%;\n}\n.btn-group-justified > .btn-group .btn {\n  width: 100%;\n}\n.btn-group-justified > .btn-group .dropdown-menu {\n  left: auto;\n}\n\n[data-toggle=\"buttons\"] > .btn > input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn > input[type=\"checkbox\"] {\n  position: absolute;\n  z-index: -1;\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n\n.input-group {\n  position: relative;\n  display: table;\n  border-collapse: separate;\n}\n.input-group[class*=\"col-\"] {\n  float: none;\n  padding-left: 0;\n  padding-right: 0;\n}\n.input-group .form-control {\n  position: relative;\n  z-index: 2;\n  float: left;\n  width: 100%;\n  margin-bottom: 0;\n}\n\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n  display: table-cell;\n}\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n\n.input-group-addon,\n.input-group-btn {\n  width: 1%;\n  white-space: nowrap;\n  vertical-align: middle;\n}\n\n.input-group-addon {\n  padding: 6px 12px;\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 1;\n  color: #555555;\n  text-align: center;\n  background-color: #eeeeee;\n  border: 1px solid #ccc;\n  border-radius: 4px;\n}\n.input-group-addon.input-sm, .form-horizontal .form-group-sm .input-group-addon.form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .input-group-addon.btn {\n  padding: 5px 10px;\n  font-size: 12px;\n  border-radius: 3px;\n}\n.input-group-addon.input-lg, .form-horizontal .form-group-lg .input-group-addon.form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .input-group-addon.btn {\n  padding: 10px 16px;\n  font-size: 18px;\n  border-radius: 6px;\n}\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n  margin-top: 0;\n}\n\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-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n\n.input-group-addon:first-child {\n  border-right: 0;\n}\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-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n}\n\n.input-group-addon:last-child {\n  border-left: 0;\n}\n\n.input-group-btn {\n  position: relative;\n  font-size: 0;\n  white-space: nowrap;\n}\n.input-group-btn > .btn {\n  position: relative;\n}\n.input-group-btn > .btn + .btn {\n  margin-left: -1px;\n}\n.input-group-btn > .btn:hover, .input-group-btn > .btn:focus, .input-group-btn > .btn:active {\n  z-index: 2;\n}\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group {\n  margin-right: -1px;\n}\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group {\n  margin-left: -1px;\n}\n\n.nav {\n  margin-bottom: 0;\n  padding-left: 0;\n  list-style: none;\n}\n.nav:before, .nav:after {\n  content: \" \";\n  display: table;\n}\n.nav:after {\n  clear: both;\n}\n.nav > li {\n  position: relative;\n  display: block;\n}\n.nav > li > a {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n}\n.nav > li > a:hover, .nav > li > a:focus {\n  text-decoration: none;\n  background-color: #eeeeee;\n}\n.nav > li.disabled > a {\n  color: #777777;\n}\n.nav > li.disabled > a:hover, .nav > li.disabled > a:focus {\n  color: #777777;\n  text-decoration: none;\n  background-color: transparent;\n  cursor: not-allowed;\n}\n.nav .open > a, .nav .open > a:hover, .nav .open > a:focus {\n  background-color: #eeeeee;\n  border-color: #428bca;\n}\n.nav .nav-divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: #e5e5e5;\n}\n.nav > li > a > img {\n  max-width: none;\n}\n\n.nav-tabs {\n  border-bottom: 1px solid #ddd;\n}\n.nav-tabs > li {\n  float: left;\n  margin-bottom: -1px;\n}\n.nav-tabs > li > a {\n  margin-right: 2px;\n  line-height: 1.428571429;\n  border: 1px solid transparent;\n  border-radius: 4px 4px 0 0;\n}\n.nav-tabs > li > a:hover {\n  border-color: #eeeeee #eeeeee #ddd;\n}\n.nav-tabs > li.active > a, .nav-tabs > li.active > a:hover, .nav-tabs > li.active > a:focus {\n  color: #555555;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-bottom-color: transparent;\n  cursor: default;\n}\n\n.nav-pills > li {\n  float: left;\n}\n.nav-pills > li > a {\n  border-radius: 4px;\n}\n.nav-pills > li + li {\n  margin-left: 2px;\n}\n.nav-pills > li.active > a, .nav-pills > li.active > a:hover, .nav-pills > li.active > a:focus {\n  color: #fff;\n  background-color: #428bca;\n}\n\n.nav-stacked > li {\n  float: none;\n}\n.nav-stacked > li + li {\n  margin-top: 2px;\n  margin-left: 0;\n}\n\n.nav-justified, .nav-tabs.nav-justified {\n  width: 100%;\n}\n.nav-justified > li, .nav-tabs.nav-justified > li {\n  float: none;\n}\n.nav-justified > li > a, .nav-tabs.nav-justified > li > a {\n  text-align: center;\n  margin-bottom: 5px;\n}\n.nav-justified > .dropdown .dropdown-menu {\n  top: auto;\n  left: auto;\n}\n@media (min-width: 768px) {\n  .nav-justified > li, .nav-tabs.nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n  .nav-justified > li > a, .nav-tabs.nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n\n.nav-tabs-justified, .nav-tabs.nav-justified {\n  border-bottom: 0;\n}\n.nav-tabs-justified > li > a, .nav-tabs.nav-justified > li > a {\n  margin-right: 0;\n  border-radius: 4px;\n}\n.nav-tabs-justified > .active > a, .nav-tabs.nav-justified > .active > a,\n.nav-tabs-justified > .active > a:hover,\n.nav-tabs.nav-justified > .active > a:hover,\n.nav-tabs-justified > .active > a:focus,\n.nav-tabs.nav-justified > .active > a:focus {\n  border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n  .nav-tabs-justified > li > a, .nav-tabs.nav-justified > li > a {\n    border-bottom: 1px solid #ddd;\n    border-radius: 4px 4px 0 0;\n  }\n  .nav-tabs-justified > .active > a, .nav-tabs.nav-justified > .active > a,\n  .nav-tabs-justified > .active > a:hover,\n  .nav-tabs.nav-justified > .active > a:hover,\n  .nav-tabs-justified > .active > a:focus,\n  .nav-tabs.nav-justified > .active > a:focus {\n    border-bottom-color: #fff;\n  }\n}\n\n.tab-content > .tab-pane {\n  display: none;\n}\n.tab-content > .active {\n  display: block;\n}\n\n.nav-tabs .dropdown-menu {\n  margin-top: -1px;\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n\n.navbar {\n  position: relative;\n  min-height: 50px;\n  margin-bottom: 20px;\n  border: 1px solid transparent;\n}\n.navbar:before, .navbar:after {\n  content: \" \";\n  display: table;\n}\n.navbar:after {\n  clear: both;\n}\n@media (min-width: 768px) {\n  .navbar {\n    border-radius: 4px;\n  }\n}\n\n.navbar-header:before, .navbar-header:after {\n  content: \" \";\n  display: table;\n}\n.navbar-header:after {\n  clear: both;\n}\n@media (min-width: 768px) {\n  .navbar-header {\n    float: left;\n  }\n}\n\n.navbar-collapse {\n  overflow-x: visible;\n  padding-right: 15px;\n  padding-left: 15px;\n  border-top: 1px solid transparent;\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\n  -webkit-overflow-scrolling: touch;\n}\n.navbar-collapse:before, .navbar-collapse:after {\n  content: \" \";\n  display: table;\n}\n.navbar-collapse:after {\n  clear: both;\n}\n.navbar-collapse.in {\n  overflow-y: auto;\n}\n@media (min-width: 768px) {\n  .navbar-collapse {\n    width: auto;\n    border-top: 0;\n    box-shadow: none;\n  }\n  .navbar-collapse.collapse {\n    display: block !important;\n    height: auto !important;\n    padding-bottom: 0;\n    overflow: visible !important;\n  }\n  .navbar-collapse.in {\n    overflow-y: visible;\n  }\n  .navbar-fixed-top .navbar-collapse, .navbar-static-top .navbar-collapse, .navbar-fixed-bottom .navbar-collapse {\n    padding-left: 0;\n    padding-right: 0;\n  }\n}\n\n.navbar-fixed-top .navbar-collapse,\n.navbar-fixed-bottom .navbar-collapse {\n  max-height: 340px;\n}\n@media (max-width: 480px) and (orientation: landscape) {\n  .navbar-fixed-top .navbar-collapse,\n  .navbar-fixed-bottom .navbar-collapse {\n    max-height: 200px;\n  }\n}\n\n.container > .navbar-header,\n.container > .navbar-collapse,\n.container-fluid > .navbar-header,\n.container-fluid > .navbar-collapse {\n  margin-right: -15px;\n  margin-left: -15px;\n}\n@media (min-width: 768px) {\n  .container > .navbar-header,\n  .container > .navbar-collapse,\n  .container-fluid > .navbar-header,\n  .container-fluid > .navbar-collapse {\n    margin-right: 0;\n    margin-left: 0;\n  }\n}\n\n.navbar-static-top {\n  z-index: 1000;\n  border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n  .navbar-static-top {\n    border-radius: 0;\n  }\n}\n\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  position: fixed;\n  right: 0;\n  left: 0;\n  z-index: 1030;\n  -webkit-transform: translate3d(0, 0, 0);\n  transform: translate3d(0, 0, 0);\n}\n@media (min-width: 768px) {\n  .navbar-fixed-top,\n  .navbar-fixed-bottom {\n    border-radius: 0;\n  }\n}\n\n.navbar-fixed-top {\n  top: 0;\n  border-width: 0 0 1px;\n}\n\n.navbar-fixed-bottom {\n  bottom: 0;\n  margin-bottom: 0;\n  border-width: 1px 0 0;\n}\n\n.navbar-brand {\n  float: left;\n  padding: 15px 15px;\n  font-size: 18px;\n  line-height: 20px;\n  height: 50px;\n}\n.navbar-brand:hover, .navbar-brand:focus {\n  text-decoration: none;\n}\n@media (min-width: 768px) {\n  .navbar > .container .navbar-brand, .navbar > .container-fluid .navbar-brand {\n    margin-left: -15px;\n  }\n}\n\n.navbar-toggle {\n  position: relative;\n  float: right;\n  margin-right: 15px;\n  padding: 9px 10px;\n  margin-top: 8px;\n  margin-bottom: 8px;\n  background-color: transparent;\n  background-image: none;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.navbar-toggle:focus {\n  outline: 0;\n}\n.navbar-toggle .icon-bar {\n  display: block;\n  width: 22px;\n  height: 2px;\n  border-radius: 1px;\n}\n.navbar-toggle .icon-bar + .icon-bar {\n  margin-top: 4px;\n}\n@media (min-width: 768px) {\n  .navbar-toggle {\n    display: none;\n  }\n}\n\n.navbar-nav {\n  margin: 7.5px -15px;\n}\n.navbar-nav > li > a {\n  padding-top: 10px;\n  padding-bottom: 10px;\n  line-height: 20px;\n}\n@media (max-width: 767px) {\n  .navbar-nav .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  }\n  .navbar-nav .open .dropdown-menu > li > a,\n  .navbar-nav .open .dropdown-menu .dropdown-header {\n    padding: 5px 15px 5px 25px;\n  }\n  .navbar-nav .open .dropdown-menu > li > a {\n    line-height: 20px;\n  }\n  .navbar-nav .open .dropdown-menu > li > a:hover, .navbar-nav .open .dropdown-menu > li > a:focus {\n    background-image: none;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-nav {\n    float: left;\n    margin: 0;\n  }\n  .navbar-nav > li {\n    float: left;\n  }\n  .navbar-nav > li > a {\n    padding-top: 15px;\n    padding-bottom: 15px;\n  }\n  .navbar-nav.navbar-right:last-child {\n    margin-right: -15px;\n  }\n}\n\n@media (min-width: 768px) {\n  .navbar-left {\n    float: left !important;\n  }\n\n  .navbar-right {\n    float: right !important;\n  }\n}\n.navbar-form {\n  margin-left: -15px;\n  margin-right: -15px;\n  padding: 10px 15px;\n  border-top: 1px solid transparent;\n  border-bottom: 1px solid transparent;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n  margin-top: 8px;\n  margin-bottom: 8px;\n}\n@media (max-width: 767px) {\n  .navbar-form .form-group {\n    margin-bottom: 5px;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-form {\n    width: auto;\n    border: 0;\n    margin-left: 0;\n    margin-right: 0;\n    padding-top: 0;\n    padding-bottom: 0;\n    -webkit-box-shadow: none;\n    box-shadow: none;\n  }\n  .navbar-form.navbar-right:last-child {\n    margin-right: -15px;\n  }\n}\n\n.navbar-nav > li > .dropdown-menu {\n  margin-top: 0;\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n\n.navbar-btn {\n  margin-top: 8px;\n  margin-bottom: 8px;\n}\n.navbar-btn.btn-sm, .btn-group-sm > .navbar-btn.btn {\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n.navbar-btn.btn-xs, .btn-group-xs > .navbar-btn.btn {\n  margin-top: 14px;\n  margin-bottom: 14px;\n}\n\n.navbar-text {\n  margin-top: 15px;\n  margin-bottom: 15px;\n}\n@media (min-width: 768px) {\n  .navbar-text {\n    float: left;\n    margin-left: 15px;\n    margin-right: 15px;\n  }\n  .navbar-text.navbar-right:last-child {\n    margin-right: 0;\n  }\n}\n\n.navbar-default {\n  background-color: #f8f8f8;\n  border-color: #e7e7e7;\n}\n.navbar-default .navbar-brand {\n  color: #777;\n}\n.navbar-default .navbar-brand:hover, .navbar-default .navbar-brand:focus {\n  color: #5e5e5e;\n  background-color: transparent;\n}\n.navbar-default .navbar-text {\n  color: #777;\n}\n.navbar-default .navbar-nav > li > a {\n  color: #777;\n}\n.navbar-default .navbar-nav > li > a:hover, .navbar-default .navbar-nav > li > a:focus {\n  color: #333;\n  background-color: transparent;\n}\n.navbar-default .navbar-nav > .active > a, .navbar-default .navbar-nav > .active > a:hover, .navbar-default .navbar-nav > .active > a:focus {\n  color: #555;\n  background-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .disabled > a, .navbar-default .navbar-nav > .disabled > a:hover, .navbar-default .navbar-nav > .disabled > a:focus {\n  color: #ccc;\n  background-color: transparent;\n}\n.navbar-default .navbar-toggle {\n  border-color: #ddd;\n}\n.navbar-default .navbar-toggle:hover, .navbar-default .navbar-toggle:focus {\n  background-color: #ddd;\n}\n.navbar-default .navbar-toggle .icon-bar {\n  background-color: #888;\n}\n.navbar-default .navbar-collapse,\n.navbar-default .navbar-form {\n  border-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .open > a, .navbar-default .navbar-nav > .open > a:hover, .navbar-default .navbar-nav > .open > a:focus {\n  background-color: #e7e7e7;\n  color: #555;\n}\n@media (max-width: 767px) {\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n    color: #777;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: #333;\n    background-color: transparent;\n  }\n  .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 {\n    color: #555;\n    background-color: #e7e7e7;\n  }\n  .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 {\n    color: #ccc;\n    background-color: transparent;\n  }\n}\n.navbar-default .navbar-link {\n  color: #777;\n}\n.navbar-default .navbar-link:hover {\n  color: #333;\n}\n.navbar-default .btn-link {\n  color: #777;\n}\n.navbar-default .btn-link:hover, .navbar-default .btn-link:focus {\n  color: #333;\n}\n.navbar-default .btn-link[disabled]:hover, .navbar-default .btn-link[disabled]:focus, fieldset[disabled] .navbar-default .btn-link:hover, fieldset[disabled] .navbar-default .btn-link:focus {\n  color: #ccc;\n}\n\n.navbar-inverse {\n  background-color: #222;\n  border-color: #090909;\n}\n.navbar-inverse .navbar-brand {\n  color: #777777;\n}\n.navbar-inverse .navbar-brand:hover, .navbar-inverse .navbar-brand:focus {\n  color: #fff;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-text {\n  color: #777777;\n}\n.navbar-inverse .navbar-nav > li > a {\n  color: #777777;\n}\n.navbar-inverse .navbar-nav > li > a:hover, .navbar-inverse .navbar-nav > li > a:focus {\n  color: #fff;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .active > a, .navbar-inverse .navbar-nav > .active > a:hover, .navbar-inverse .navbar-nav > .active > a:focus {\n  color: #fff;\n  background-color: #090909;\n}\n.navbar-inverse .navbar-nav > .disabled > a, .navbar-inverse .navbar-nav > .disabled > a:hover, .navbar-inverse .navbar-nav > .disabled > a:focus {\n  color: #444;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-toggle {\n  border-color: #333;\n}\n.navbar-inverse .navbar-toggle:hover, .navbar-inverse .navbar-toggle:focus {\n  background-color: #333;\n}\n.navbar-inverse .navbar-toggle .icon-bar {\n  background-color: #fff;\n}\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n  border-color: #101010;\n}\n.navbar-inverse .navbar-nav > .open > a, .navbar-inverse .navbar-nav > .open > a:hover, .navbar-inverse .navbar-nav > .open > a:focus {\n  background-color: #090909;\n  color: #fff;\n}\n@media (max-width: 767px) {\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n    border-color: #090909;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n    background-color: #090909;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n    color: #777777;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: #fff;\n    background-color: transparent;\n  }\n  .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 {\n    color: #fff;\n    background-color: #090909;\n  }\n  .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 {\n    color: #444;\n    background-color: transparent;\n  }\n}\n.navbar-inverse .navbar-link {\n  color: #777777;\n}\n.navbar-inverse .navbar-link:hover {\n  color: #fff;\n}\n.navbar-inverse .btn-link {\n  color: #777777;\n}\n.navbar-inverse .btn-link:hover, .navbar-inverse .btn-link:focus {\n  color: #fff;\n}\n.navbar-inverse .btn-link[disabled]:hover, .navbar-inverse .btn-link[disabled]:focus, fieldset[disabled] .navbar-inverse .btn-link:hover, fieldset[disabled] .navbar-inverse .btn-link:focus {\n  color: #444;\n}\n\n.breadcrumb {\n  padding: 8px 15px;\n  margin-bottom: 20px;\n  list-style: none;\n  background-color: #f5f5f5;\n  border-radius: 4px;\n}\n.breadcrumb > li {\n  display: inline-block;\n}\n.breadcrumb > li + li:before {\n  content: \"/ \";\n  padding: 0 5px;\n  color: #ccc;\n}\n.breadcrumb > .active {\n  color: #777777;\n}\n\n.pagination {\n  display: inline-block;\n  padding-left: 0;\n  margin: 20px 0;\n  border-radius: 4px;\n}\n.pagination > li {\n  display: inline;\n}\n.pagination > li > a,\n.pagination > li > span {\n  position: relative;\n  float: left;\n  padding: 6px 12px;\n  line-height: 1.428571429;\n  text-decoration: none;\n  color: #428bca;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  margin-left: -1px;\n}\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n  margin-left: 0;\n  border-bottom-left-radius: 4px;\n  border-top-left-radius: 4px;\n}\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n  border-bottom-right-radius: 4px;\n  border-top-right-radius: 4px;\n}\n.pagination > li > a:hover, .pagination > li > a:focus,\n.pagination > li > span:hover,\n.pagination > li > span:focus {\n  color: #2a6496;\n  background-color: #eeeeee;\n  border-color: #ddd;\n}\n.pagination > .active > a, .pagination > .active > a:hover, .pagination > .active > a:focus,\n.pagination > .active > span,\n.pagination > .active > span:hover,\n.pagination > .active > span:focus {\n  z-index: 2;\n  color: #fff;\n  background-color: #428bca;\n  border-color: #428bca;\n  cursor: default;\n}\n.pagination > .disabled > span,\n.pagination > .disabled > span:hover,\n.pagination > .disabled > span:focus,\n.pagination > .disabled > a,\n.pagination > .disabled > a:hover,\n.pagination > .disabled > a:focus {\n  color: #777777;\n  background-color: #fff;\n  border-color: #ddd;\n  cursor: not-allowed;\n}\n\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n  padding: 10px 16px;\n  font-size: 18px;\n}\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n  border-bottom-left-radius: 6px;\n  border-top-left-radius: 6px;\n}\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n  border-bottom-right-radius: 6px;\n  border-top-right-radius: 6px;\n}\n\n.pagination-sm > li > a,\n.pagination-sm > li > span {\n  padding: 5px 10px;\n  font-size: 12px;\n}\n.pagination-sm > li:first-child > a,\n.pagination-sm > li:first-child > span {\n  border-bottom-left-radius: 3px;\n  border-top-left-radius: 3px;\n}\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n  border-bottom-right-radius: 3px;\n  border-top-right-radius: 3px;\n}\n\n.pager {\n  padding-left: 0;\n  margin: 20px 0;\n  list-style: none;\n  text-align: center;\n}\n.pager:before, .pager:after {\n  content: \" \";\n  display: table;\n}\n.pager:after {\n  clear: both;\n}\n.pager li {\n  display: inline;\n}\n.pager li > a,\n.pager li > span {\n  display: inline-block;\n  padding: 5px 14px;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-radius: 15px;\n}\n.pager li > a:hover,\n.pager li > a:focus {\n  text-decoration: none;\n  background-color: #eeeeee;\n}\n.pager .next > a,\n.pager .next > span {\n  float: right;\n}\n.pager .previous > a,\n.pager .previous > span {\n  float: left;\n}\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n  color: #777777;\n  background-color: #fff;\n  cursor: not-allowed;\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: #fff;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: baseline;\n  border-radius: .25em;\n}\n.label:empty {\n  display: none;\n}\n.btn .label {\n  position: relative;\n  top: -1px;\n}\n\na.label:hover, a.label:focus {\n  color: #fff;\n  text-decoration: none;\n  cursor: pointer;\n}\n\n.label-default {\n  background-color: #777777;\n}\n.label-default[href]:hover, .label-default[href]:focus {\n  background-color: #5e5e5e;\n}\n\n.label-primary {\n  background-color: #428bca;\n}\n.label-primary[href]:hover, .label-primary[href]:focus {\n  background-color: #3071a9;\n}\n\n.label-success {\n  background-color: #5cb85c;\n}\n.label-success[href]:hover, .label-success[href]:focus {\n  background-color: #449d44;\n}\n\n.label-info {\n  background-color: #5bc0de;\n}\n.label-info[href]:hover, .label-info[href]:focus {\n  background-color: #31b0d5;\n}\n\n.label-warning {\n  background-color: #f0ad4e;\n}\n.label-warning[href]:hover, .label-warning[href]:focus {\n  background-color: #ec971f;\n}\n\n.label-danger {\n  background-color: #d9534f;\n}\n.label-danger[href]:hover, .label-danger[href]:focus {\n  background-color: #c9302c;\n}\n\n.badge {\n  display: inline-block;\n  min-width: 10px;\n  padding: 3px 7px;\n  font-size: 12px;\n  font-weight: bold;\n  color: #fff;\n  line-height: 1;\n  vertical-align: baseline;\n  white-space: nowrap;\n  text-align: center;\n  background-color: #777777;\n  border-radius: 10px;\n}\n.badge:empty {\n  display: none;\n}\n.btn .badge {\n  position: relative;\n  top: -1px;\n}\n.btn-xs .badge, .btn-group-xs > .btn .badge {\n  top: 0;\n  padding: 1px 5px;\n}\na.list-group-item.active > .badge, .nav-pills > .active > a > .badge {\n  color: #428bca;\n  background-color: #fff;\n}\n.nav-pills > li > a > .badge {\n  margin-left: 3px;\n}\n\na.badge:hover, a.badge:focus {\n  color: #fff;\n  text-decoration: none;\n  cursor: pointer;\n}\n\n.jumbotron {\n  padding: 30px;\n  margin-bottom: 30px;\n  color: inherit;\n  background-color: #eeeeee;\n}\n.jumbotron h1,\n.jumbotron .h1 {\n  color: inherit;\n}\n.jumbotron p {\n  margin-bottom: 15px;\n  font-size: 21px;\n  font-weight: 200;\n}\n.jumbotron > hr {\n  border-top-color: #d5d5d5;\n}\n.container .jumbotron {\n  border-radius: 6px;\n}\n.jumbotron .container {\n  max-width: 100%;\n}\n@media screen and (min-width: 768px) {\n  .jumbotron {\n    padding-top: 48px;\n    padding-bottom: 48px;\n  }\n  .container .jumbotron {\n    padding-left: 60px;\n    padding-right: 60px;\n  }\n  .jumbotron h1,\n  .jumbotron .h1 {\n    font-size: 63px;\n  }\n}\n\n.thumbnail {\n  display: block;\n  padding: 4px;\n  margin-bottom: 20px;\n  line-height: 1.428571429;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-radius: 4px;\n  -webkit-transition: all 0.2s ease-in-out;\n  -o-transition: all 0.2s ease-in-out;\n  transition: all 0.2s ease-in-out;\n}\n.thumbnail > img,\n.thumbnail a > img {\n  display: block;\n  width: 100% \\9;\n  max-width: 100%;\n  height: auto;\n  margin-left: auto;\n  margin-right: auto;\n}\n.thumbnail .caption {\n  padding: 9px;\n  color: #333333;\n}\n\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n  border-color: #428bca;\n}\n\n.alert {\n  padding: 15px;\n  margin-bottom: 20px;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.alert h4 {\n  margin-top: 0;\n  color: inherit;\n}\n.alert .alert-link {\n  font-weight: bold;\n}\n.alert > p,\n.alert > ul {\n  margin-bottom: 0;\n}\n.alert > p + p {\n  margin-top: 5px;\n}\n\n.alert-dismissable,\n.alert-dismissible {\n  padding-right: 35px;\n}\n.alert-dismissable .close,\n.alert-dismissible .close {\n  position: relative;\n  top: -2px;\n  right: -21px;\n  color: inherit;\n}\n\n.alert-success {\n  background-color: #dff0d8;\n  border-color: #d6e9c6;\n  color: #3c763d;\n}\n.alert-success hr {\n  border-top-color: #c9e2b3;\n}\n.alert-success .alert-link {\n  color: #2b542c;\n}\n\n.alert-info {\n  background-color: #d9edf7;\n  border-color: #bce8f1;\n  color: #31708f;\n}\n.alert-info hr {\n  border-top-color: #a6e1ec;\n}\n.alert-info .alert-link {\n  color: #245269;\n}\n\n.alert-warning {\n  background-color: #fcf8e3;\n  border-color: #faebcc;\n  color: #8a6d3b;\n}\n.alert-warning hr {\n  border-top-color: #f7e1b5;\n}\n.alert-warning .alert-link {\n  color: #66512c;\n}\n\n.alert-danger {\n  background-color: #f2dede;\n  border-color: #ebccd1;\n  color: #a94442;\n}\n.alert-danger hr {\n  border-top-color: #e4b9c0;\n}\n.alert-danger .alert-link {\n  color: #843534;\n}\n\n@-webkit-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n@keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n.progress {\n  overflow: hidden;\n  height: 20px;\n  margin-bottom: 20px;\n  background-color: #f5f5f5;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n\n.progress-bar {\n  float: left;\n  width: 0%;\n  height: 100%;\n  font-size: 12px;\n  line-height: 20px;\n  color: #fff;\n  text-align: center;\n  background-color: #428bca;\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  -webkit-transition: width 0.6s ease;\n  -o-transition: width 0.6s ease;\n  transition: width 0.6s ease;\n}\n\n.progress-striped .progress-bar,\n.progress-bar-striped {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, rgba(0, 0, 0, 0) 25%, rgba(0, 0, 0, 0) 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, rgba(0, 0, 0, 0) 75%, rgba(0, 0, 0, 0));\n  background-size: 40px 40px;\n}\n\n.progress.active .progress-bar,\n.progress-bar.active {\n  -webkit-animation: progress-bar-stripes 2s linear infinite;\n  -o-animation: progress-bar-stripes 2s linear infinite;\n  animation: progress-bar-stripes 2s linear infinite;\n}\n\n.progress-bar[aria-valuenow=\"1\"], .progress-bar[aria-valuenow=\"2\"] {\n  min-width: 30px;\n}\n.progress-bar[aria-valuenow=\"0\"] {\n  color: #777777;\n  min-width: 30px;\n  background-color: transparent;\n  background-image: none;\n  box-shadow: none;\n}\n\n.progress-bar-success {\n  background-color: #5cb85c;\n}\n.progress-striped .progress-bar-success {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, rgba(0, 0, 0, 0) 25%, rgba(0, 0, 0, 0) 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, rgba(0, 0, 0, 0) 75%, rgba(0, 0, 0, 0));\n}\n\n.progress-bar-info {\n  background-color: #5bc0de;\n}\n.progress-striped .progress-bar-info {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, rgba(0, 0, 0, 0) 25%, rgba(0, 0, 0, 0) 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, rgba(0, 0, 0, 0) 75%, rgba(0, 0, 0, 0));\n}\n\n.progress-bar-warning {\n  background-color: #f0ad4e;\n}\n.progress-striped .progress-bar-warning {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, rgba(0, 0, 0, 0) 25%, rgba(0, 0, 0, 0) 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, rgba(0, 0, 0, 0) 75%, rgba(0, 0, 0, 0));\n}\n\n.progress-bar-danger {\n  background-color: #d9534f;\n}\n.progress-striped .progress-bar-danger {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, rgba(0, 0, 0, 0) 25%, rgba(0, 0, 0, 0) 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, rgba(0, 0, 0, 0) 75%, rgba(0, 0, 0, 0));\n}\n\n.media,\n.media-body {\n  overflow: hidden;\n  zoom: 1;\n}\n\n.media,\n.media .media {\n  margin-top: 15px;\n}\n\n.media:first-child {\n  margin-top: 0;\n}\n\n.media-object {\n  display: block;\n}\n\n.media-heading {\n  margin: 0 0 5px;\n}\n\n.media > .pull-left {\n  margin-right: 10px;\n}\n.media > .pull-right {\n  margin-left: 10px;\n}\n\n.media-list {\n  padding-left: 0;\n  list-style: none;\n}\n\n.list-group {\n  margin-bottom: 20px;\n  padding-left: 0;\n}\n\n.list-group-item {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n  margin-bottom: -1px;\n  background-color: #fff;\n  border: 1px solid #ddd;\n}\n.list-group-item:first-child {\n  border-top-right-radius: 4px;\n  border-top-left-radius: 4px;\n}\n.list-group-item:last-child {\n  margin-bottom: 0;\n  border-bottom-right-radius: 4px;\n  border-bottom-left-radius: 4px;\n}\n.list-group-item > .badge {\n  float: right;\n}\n.list-group-item > .badge + .badge {\n  margin-right: 5px;\n}\n\na.list-group-item {\n  color: #555;\n}\na.list-group-item .list-group-item-heading {\n  color: #333;\n}\na.list-group-item:hover, a.list-group-item:focus {\n  text-decoration: none;\n  color: #555;\n  background-color: #f5f5f5;\n}\n\n.list-group-item.disabled, .list-group-item.disabled:hover, .list-group-item.disabled:focus {\n  background-color: #eeeeee;\n  color: #777777;\n}\n.list-group-item.disabled .list-group-item-heading, .list-group-item.disabled:hover .list-group-item-heading, .list-group-item.disabled:focus .list-group-item-heading {\n  color: inherit;\n}\n.list-group-item.disabled .list-group-item-text, .list-group-item.disabled:hover .list-group-item-text, .list-group-item.disabled:focus .list-group-item-text {\n  color: #777777;\n}\n.list-group-item.active, .list-group-item.active:hover, .list-group-item.active:focus {\n  z-index: 2;\n  color: #fff;\n  background-color: #428bca;\n  border-color: #428bca;\n}\n.list-group-item.active .list-group-item-heading,\n.list-group-item.active .list-group-item-heading > small,\n.list-group-item.active .list-group-item-heading > .small, .list-group-item.active:hover .list-group-item-heading,\n.list-group-item.active:hover .list-group-item-heading > small,\n.list-group-item.active:hover .list-group-item-heading > .small, .list-group-item.active:focus .list-group-item-heading,\n.list-group-item.active:focus .list-group-item-heading > small,\n.list-group-item.active:focus .list-group-item-heading > .small {\n  color: inherit;\n}\n.list-group-item.active .list-group-item-text, .list-group-item.active:hover .list-group-item-text, .list-group-item.active:focus .list-group-item-text {\n  color: #e1edf7;\n}\n\n.list-group-item-success {\n  color: #3c763d;\n  background-color: #dff0d8;\n}\n\na.list-group-item-success {\n  color: #3c763d;\n}\na.list-group-item-success .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-success:hover, a.list-group-item-success:focus {\n  color: #3c763d;\n  background-color: #d0e9c6;\n}\na.list-group-item-success.active, a.list-group-item-success.active:hover, a.list-group-item-success.active:focus {\n  color: #fff;\n  background-color: #3c763d;\n  border-color: #3c763d;\n}\n\n.list-group-item-info {\n  color: #31708f;\n  background-color: #d9edf7;\n}\n\na.list-group-item-info {\n  color: #31708f;\n}\na.list-group-item-info .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-info:hover, a.list-group-item-info:focus {\n  color: #31708f;\n  background-color: #c4e3f3;\n}\na.list-group-item-info.active, a.list-group-item-info.active:hover, a.list-group-item-info.active:focus {\n  color: #fff;\n  background-color: #31708f;\n  border-color: #31708f;\n}\n\n.list-group-item-warning {\n  color: #8a6d3b;\n  background-color: #fcf8e3;\n}\n\na.list-group-item-warning {\n  color: #8a6d3b;\n}\na.list-group-item-warning .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-warning:hover, a.list-group-item-warning:focus {\n  color: #8a6d3b;\n  background-color: #faf2cc;\n}\na.list-group-item-warning.active, a.list-group-item-warning.active:hover, a.list-group-item-warning.active:focus {\n  color: #fff;\n  background-color: #8a6d3b;\n  border-color: #8a6d3b;\n}\n\n.list-group-item-danger {\n  color: #a94442;\n  background-color: #f2dede;\n}\n\na.list-group-item-danger {\n  color: #a94442;\n}\na.list-group-item-danger .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-danger:hover, a.list-group-item-danger:focus {\n  color: #a94442;\n  background-color: #ebcccc;\n}\na.list-group-item-danger.active, a.list-group-item-danger.active:hover, a.list-group-item-danger.active:focus {\n  color: #fff;\n  background-color: #a94442;\n  border-color: #a94442;\n}\n\n.list-group-item-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n\n.list-group-item-text {\n  margin-bottom: 0;\n  line-height: 1.3;\n}\n\n.panel {\n  margin-bottom: 20px;\n  background-color: #fff;\n  border: 1px solid transparent;\n  border-radius: 4px;\n  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n\n.panel-body {\n  padding: 15px;\n}\n.panel-body:before, .panel-body:after {\n  content: \" \";\n  display: table;\n}\n.panel-body:after {\n  clear: both;\n}\n\n.panel-heading {\n  padding: 10px 15px;\n  border-bottom: 1px solid transparent;\n  border-top-right-radius: 3px;\n  border-top-left-radius: 3px;\n}\n.panel-heading > .dropdown .dropdown-toggle {\n  color: inherit;\n}\n\n.panel-title {\n  margin-top: 0;\n  margin-bottom: 0;\n  font-size: 16px;\n  color: inherit;\n}\n.panel-title > a {\n  color: inherit;\n}\n\n.panel-footer {\n  padding: 10px 15px;\n  background-color: #f5f5f5;\n  border-top: 1px solid #ddd;\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n\n.panel > .list-group {\n  margin-bottom: 0;\n}\n.panel > .list-group .list-group-item {\n  border-width: 1px 0;\n  border-radius: 0;\n}\n.panel > .list-group:first-child .list-group-item:first-child {\n  border-top: 0;\n  border-top-right-radius: 3px;\n  border-top-left-radius: 3px;\n}\n.panel > .list-group:last-child .list-group-item:last-child {\n  border-bottom: 0;\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n\n.panel-heading + .list-group .list-group-item:first-child {\n  border-top-width: 0;\n}\n\n.list-group + .panel-footer {\n  border-top-width: 0;\n}\n\n.panel > .table,\n.panel > .table-responsive > .table,\n.panel > .panel-collapse > .table {\n  margin-bottom: 0;\n}\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n  border-top-right-radius: 3px;\n  border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\n  border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\n  border-top-right-radius: 3px;\n}\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n  border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n  border-bottom-right-radius: 3px;\n}\n.panel > .panel-body + .table,\n.panel > .panel-body + .table-responsive {\n  border-top: 1px solid #ddd;\n}\n.panel > .table > tbody:first-child > tr:first-child th,\n.panel > .table > tbody:first-child > tr:first-child td {\n  border-top: 0;\n}\n.panel > .table-bordered,\n.panel > .table-responsive > .table-bordered {\n  border: 0;\n}\n.panel > .table-bordered > thead > tr > th:first-child,\n.panel > .table-bordered > thead > tr > td:first-child,\n.panel > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-bordered > tfoot > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n  border-left: 0;\n}\n.panel > .table-bordered > thead > tr > th:last-child,\n.panel > .table-bordered > thead > tr > td:last-child,\n.panel > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-bordered > tfoot > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n  border-right: 0;\n}\n.panel > .table-bordered > thead > tr:first-child > td,\n.panel > .table-bordered > thead > tr:first-child > th,\n.panel > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-bordered > tbody > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\n  border-bottom: 0;\n}\n.panel > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-bordered > tfoot > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n  border-bottom: 0;\n}\n.panel > .table-responsive {\n  border: 0;\n  margin-bottom: 0;\n}\n\n.panel-group {\n  margin-bottom: 20px;\n}\n.panel-group .panel {\n  margin-bottom: 0;\n  border-radius: 4px;\n}\n.panel-group .panel + .panel {\n  margin-top: 5px;\n}\n.panel-group .panel-heading {\n  border-bottom: 0;\n}\n.panel-group .panel-heading + .panel-collapse > .panel-body {\n  border-top: 1px solid #ddd;\n}\n.panel-group .panel-footer {\n  border-top: 0;\n}\n.panel-group .panel-footer + .panel-collapse .panel-body {\n  border-bottom: 1px solid #ddd;\n}\n\n.panel-default {\n  border-color: #ddd;\n}\n.panel-default > .panel-heading {\n  color: #333333;\n  background-color: #f5f5f5;\n  border-color: #ddd;\n}\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #ddd;\n}\n.panel-default > .panel-heading .badge {\n  color: #f5f5f5;\n  background-color: #333333;\n}\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #ddd;\n}\n\n.panel-primary {\n  border-color: #428bca;\n}\n.panel-primary > .panel-heading {\n  color: #fff;\n  background-color: #428bca;\n  border-color: #428bca;\n}\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #428bca;\n}\n.panel-primary > .panel-heading .badge {\n  color: #428bca;\n  background-color: #fff;\n}\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #428bca;\n}\n\n.panel-success {\n  border-color: #d6e9c6;\n}\n.panel-success > .panel-heading {\n  color: #3c763d;\n  background-color: #dff0d8;\n  border-color: #d6e9c6;\n}\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #d6e9c6;\n}\n.panel-success > .panel-heading .badge {\n  color: #dff0d8;\n  background-color: #3c763d;\n}\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #d6e9c6;\n}\n\n.panel-info {\n  border-color: #bce8f1;\n}\n.panel-info > .panel-heading {\n  color: #31708f;\n  background-color: #d9edf7;\n  border-color: #bce8f1;\n}\n.panel-info > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #bce8f1;\n}\n.panel-info > .panel-heading .badge {\n  color: #d9edf7;\n  background-color: #31708f;\n}\n.panel-info > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #bce8f1;\n}\n\n.panel-warning {\n  border-color: #faebcc;\n}\n.panel-warning > .panel-heading {\n  color: #8a6d3b;\n  background-color: #fcf8e3;\n  border-color: #faebcc;\n}\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #faebcc;\n}\n.panel-warning > .panel-heading .badge {\n  color: #fcf8e3;\n  background-color: #8a6d3b;\n}\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #faebcc;\n}\n\n.panel-danger {\n  border-color: #ebccd1;\n}\n.panel-danger > .panel-heading {\n  color: #a94442;\n  background-color: #f2dede;\n  border-color: #ebccd1;\n}\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #ebccd1;\n}\n.panel-danger > .panel-heading .badge {\n  color: #f2dede;\n  background-color: #a94442;\n}\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #ebccd1;\n}\n\n.embed-responsive {\n  position: relative;\n  display: block;\n  height: 0;\n  padding: 0;\n  overflow: hidden;\n}\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  height: 100%;\n  width: 100%;\n  border: 0;\n}\n.embed-responsive.embed-responsive-16by9 {\n  padding-bottom: 56.25%;\n}\n.embed-responsive.embed-responsive-4by3 {\n  padding-bottom: 75%;\n}\n\n.well {\n  min-height: 20px;\n  padding: 19px;\n  margin-bottom: 20px;\n  background-color: #f5f5f5;\n  border: 1px solid #e3e3e3;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.well blockquote {\n  border-color: #ddd;\n  border-color: rgba(0, 0, 0, 0.15);\n}\n\n.well-lg {\n  padding: 24px;\n  border-radius: 6px;\n}\n\n.well-sm {\n  padding: 9px;\n  border-radius: 3px;\n}\n\n.close {\n  float: right;\n  font-size: 21px;\n  font-weight: bold;\n  line-height: 1;\n  color: #000;\n  text-shadow: 0 1px 0 #fff;\n  opacity: 0.2;\n  filter: alpha(opacity=20);\n}\n.close:hover, .close:focus {\n  color: #000;\n  text-decoration: none;\n  cursor: pointer;\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\n\nbutton.close {\n  padding: 0;\n  cursor: pointer;\n  background: transparent;\n  border: 0;\n  -webkit-appearance: none;\n}\n\n.modal-open {\n  overflow: hidden;\n}\n\n.modal {\n  display: none;\n  overflow: hidden;\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1050;\n  -webkit-overflow-scrolling: touch;\n  outline: 0;\n}\n.modal.fade .modal-dialog {\n  -webkit-transform: translate3d(0, -25%, 0);\n  transform: translate3d(0, -25%, 0);\n  -webkit-transition: -webkit-transform 0.3s ease-out;\n  -moz-transition: -moz-transform 0.3s ease-out;\n  -o-transition: -o-transform 0.3s ease-out;\n  transition: transform 0.3s ease-out;\n}\n.modal.in .modal-dialog {\n  -webkit-transform: translate3d(0, 0, 0);\n  transform: translate3d(0, 0, 0);\n}\n\n.modal-open .modal {\n  overflow-x: hidden;\n  overflow-y: auto;\n}\n\n.modal-dialog {\n  position: relative;\n  width: auto;\n  margin: 10px;\n}\n\n.modal-content {\n  position: relative;\n  background-color: #fff;\n  border: 1px solid #999;\n  border: 1px solid rgba(0, 0, 0, 0.2);\n  border-radius: 6px;\n  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n  box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n  background-clip: padding-box;\n  outline: 0;\n}\n\n.modal-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1040;\n  background-color: #000;\n}\n.modal-backdrop.fade {\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n.modal-backdrop.in {\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\n\n.modal-header {\n  padding: 15px;\n  border-bottom: 1px solid #e5e5e5;\n  min-height: 16.428571429px;\n}\n\n.modal-header .close {\n  margin-top: -2px;\n}\n\n.modal-title {\n  margin: 0;\n  line-height: 1.428571429;\n}\n\n.modal-body {\n  position: relative;\n  padding: 15px;\n}\n\n.modal-footer {\n  padding: 15px;\n  text-align: right;\n  border-top: 1px solid #e5e5e5;\n}\n.modal-footer:before, .modal-footer:after {\n  content: \" \";\n  display: table;\n}\n.modal-footer:after {\n  clear: both;\n}\n.modal-footer .btn + .btn {\n  margin-left: 5px;\n  margin-bottom: 0;\n}\n.modal-footer .btn-group .btn + .btn {\n  margin-left: -1px;\n}\n.modal-footer .btn-block + .btn-block {\n  margin-left: 0;\n}\n\n.modal-scrollbar-measure {\n  position: absolute;\n  top: -9999px;\n  width: 50px;\n  height: 50px;\n  overflow: scroll;\n}\n\n@media (min-width: 768px) {\n  .modal-dialog {\n    width: 600px;\n    margin: 30px auto;\n  }\n\n  .modal-content {\n    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n  }\n\n  .modal-sm {\n    width: 300px;\n  }\n}\n@media (min-width: 992px) {\n  .modal-lg {\n    width: 900px;\n  }\n}\n.tooltip {\n  position: absolute;\n  z-index: 1070;\n  display: block;\n  visibility: visible;\n  font-size: 12px;\n  line-height: 1.4;\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n.tooltip.in {\n  opacity: 0.9;\n  filter: alpha(opacity=90);\n}\n.tooltip.top {\n  margin-top: -3px;\n  padding: 5px 0;\n}\n.tooltip.right {\n  margin-left: 3px;\n  padding: 0 5px;\n}\n.tooltip.bottom {\n  margin-top: 3px;\n  padding: 5px 0;\n}\n.tooltip.left {\n  margin-left: -3px;\n  padding: 0 5px;\n}\n\n.tooltip-inner {\n  max-width: 200px;\n  padding: 3px 8px;\n  color: #fff;\n  text-align: center;\n  text-decoration: none;\n  background-color: #000;\n  border-radius: 4px;\n}\n\n.tooltip-arrow {\n  position: absolute;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n\n.tooltip.top .tooltip-arrow {\n  bottom: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000;\n}\n.tooltip.top-left .tooltip-arrow {\n  bottom: 0;\n  left: 5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000;\n}\n.tooltip.top-right .tooltip-arrow {\n  bottom: 0;\n  right: 5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000;\n}\n.tooltip.right .tooltip-arrow {\n  top: 50%;\n  left: 0;\n  margin-top: -5px;\n  border-width: 5px 5px 5px 0;\n  border-right-color: #000;\n}\n.tooltip.left .tooltip-arrow {\n  top: 50%;\n  right: 0;\n  margin-top: -5px;\n  border-width: 5px 0 5px 5px;\n  border-left-color: #000;\n}\n.tooltip.bottom .tooltip-arrow {\n  top: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n  top: 0;\n  left: 5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n  top: 0;\n  right: 5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000;\n}\n\n.popover {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 1060;\n  display: none;\n  max-width: 276px;\n  padding: 1px;\n  text-align: left;\n  background-color: #fff;\n  background-clip: padding-box;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, 0.2);\n  border-radius: 6px;\n  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n  white-space: normal;\n}\n.popover.top {\n  margin-top: -10px;\n}\n.popover.right {\n  margin-left: 10px;\n}\n.popover.bottom {\n  margin-top: 10px;\n}\n.popover.left {\n  margin-left: -10px;\n}\n\n.popover-title {\n  margin: 0;\n  padding: 8px 14px;\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 18px;\n  background-color: #f7f7f7;\n  border-bottom: 1px solid #ebebeb;\n  border-radius: 5px 5px 0 0;\n}\n\n.popover-content {\n  padding: 9px 14px;\n}\n\n.popover > .arrow, .popover > .arrow: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: 11px;\n}\n\n.popover > .arrow:after {\n  border-width: 10px;\n  content: \"\";\n}\n\n.popover.top > .arrow {\n  left: 50%;\n  margin-left: -11px;\n  border-bottom-width: 0;\n  border-top-color: #999999;\n  border-top-color: rgba(0, 0, 0, 0.25);\n  bottom: -11px;\n}\n.popover.top > .arrow:after {\n  content: \" \";\n  bottom: 1px;\n  margin-left: -10px;\n  border-bottom-width: 0;\n  border-top-color: #fff;\n}\n.popover.right > .arrow {\n  top: 50%;\n  left: -11px;\n  margin-top: -11px;\n  border-left-width: 0;\n  border-right-color: #999999;\n  border-right-color: rgba(0, 0, 0, 0.25);\n}\n.popover.right > .arrow:after {\n  content: \" \";\n  left: 1px;\n  bottom: -10px;\n  border-left-width: 0;\n  border-right-color: #fff;\n}\n.popover.bottom > .arrow {\n  left: 50%;\n  margin-left: -11px;\n  border-top-width: 0;\n  border-bottom-color: #999999;\n  border-bottom-color: rgba(0, 0, 0, 0.25);\n  top: -11px;\n}\n.popover.bottom > .arrow:after {\n  content: \" \";\n  top: 1px;\n  margin-left: -10px;\n  border-top-width: 0;\n  border-bottom-color: #fff;\n}\n.popover.left > .arrow {\n  top: 50%;\n  right: -11px;\n  margin-top: -11px;\n  border-right-width: 0;\n  border-left-color: #999999;\n  border-left-color: rgba(0, 0, 0, 0.25);\n}\n.popover.left > .arrow:after {\n  content: \" \";\n  right: 1px;\n  border-right-width: 0;\n  border-left-color: #fff;\n  bottom: -10px;\n}\n\n.carousel {\n  position: relative;\n}\n\n.carousel-inner {\n  position: relative;\n  overflow: hidden;\n  width: 100%;\n}\n.carousel-inner > .item {\n  display: none;\n  position: relative;\n  -webkit-transition: 0.6s ease-in-out left;\n  -o-transition: 0.6s ease-in-out left;\n  transition: 0.6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n  display: block;\n  width: 100% \\9;\n  max-width: 100%;\n  height: auto;\n  line-height: 1;\n}\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n  display: block;\n}\n.carousel-inner > .active {\n  left: 0;\n}\n.carousel-inner > .next,\n.carousel-inner > .prev {\n  position: absolute;\n  top: 0;\n  width: 100%;\n}\n.carousel-inner > .next {\n  left: 100%;\n}\n.carousel-inner > .prev {\n  left: -100%;\n}\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n  left: 0;\n}\n.carousel-inner > .active.left {\n  left: -100%;\n}\n.carousel-inner > .active.right {\n  left: 100%;\n}\n\n.carousel-control {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  width: 15%;\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n  font-size: 20px;\n  color: #fff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-control.left {\n  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n  background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n}\n.carousel-control.right {\n  left: auto;\n  right: 0;\n  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n  background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n}\n.carousel-control:hover, .carousel-control:focus {\n  outline: 0;\n  color: #fff;\n  text-decoration: none;\n  opacity: 0.9;\n  filter: alpha(opacity=90);\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-left,\n.carousel-control .glyphicon-chevron-right {\n  position: absolute;\n  top: 50%;\n  z-index: 5;\n  display: inline-block;\n}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n  left: 50%;\n  margin-left: -10px;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n  right: 50%;\n  margin-right: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n  width: 20px;\n  height: 20px;\n  margin-top: -10px;\n  font-family: serif;\n}\n.carousel-control .icon-prev:before {\n  content: '\\2039';\n}\n.carousel-control .icon-next:before {\n  content: '\\203a';\n}\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.carousel-indicators li {\n  display: inline-block;\n  width: 10px;\n  height: 10px;\n  margin: 1px;\n  text-indent: -999px;\n  border: 1px solid #fff;\n  border-radius: 10px;\n  cursor: pointer;\n  background-color: #000 \\9;\n  background-color: transparent;\n}\n.carousel-indicators .active {\n  margin: 0;\n  width: 12px;\n  height: 12px;\n  background-color: #fff;\n}\n\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: #fff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-caption .btn {\n  text-shadow: none;\n}\n\n@media screen and (min-width: 768px) {\n  .carousel-control .glyphicon-chevron-left,\n  .carousel-control .glyphicon-chevron-right,\n  .carousel-control .icon-prev,\n  .carousel-control .icon-next {\n    width: 30px;\n    height: 30px;\n    margin-top: -15px;\n    font-size: 30px;\n  }\n  .carousel-control .glyphicon-chevron-left,\n  .carousel-control .icon-prev {\n    margin-left: -15px;\n  }\n  .carousel-control .glyphicon-chevron-right,\n  .carousel-control .icon-next {\n    margin-right: -15px;\n  }\n\n  .carousel-caption {\n    left: 20%;\n    right: 20%;\n    padding-bottom: 30px;\n  }\n\n  .carousel-indicators {\n    bottom: 20px;\n  }\n}\n.clearfix:before, .clearfix:after {\n  content: \" \";\n  display: table;\n}\n.clearfix:after {\n  clear: both;\n}\n\n.center-block {\n  display: block;\n  margin-left: auto;\n  margin-right: auto;\n}\n\n.pull-right {\n  float: right !important;\n}\n\n.pull-left {\n  float: left !important;\n}\n\n.hide {\n  display: none !important;\n}\n\n.show {\n  display: block !important;\n}\n\n.invisible {\n  visibility: hidden;\n}\n\n.text-hide {\n  font: 0/0 a;\n  color: transparent;\n  text-shadow: none;\n  background-color: transparent;\n  border: 0;\n}\n\n.hidden {\n  display: none !important;\n  visibility: hidden !important;\n}\n\n.affix {\n  position: fixed;\n  -webkit-transform: translate3d(0, 0, 0);\n  transform: translate3d(0, 0, 0);\n}\n\n@-ms-viewport {\n  width: device-width;\n}\n.visible-xs, .visible-sm, .visible-md, .visible-lg {\n  display: none !important;\n}\n\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n  display: none !important;\n}\n\n@media (max-width: 767px) {\n  .visible-xs {\n    display: block !important;\n  }\n\n  table.visible-xs {\n    display: table;\n  }\n\n  tr.visible-xs {\n    display: table-row !important;\n  }\n\n  th.visible-xs,\n  td.visible-xs {\n    display: table-cell !important;\n  }\n}\n@media (max-width: 767px) {\n  .visible-xs-block {\n    display: block !important;\n  }\n}\n\n@media (max-width: 767px) {\n  .visible-xs-inline {\n    display: inline !important;\n  }\n}\n\n@media (max-width: 767px) {\n  .visible-xs-inline-block {\n    display: inline-block !important;\n  }\n}\n\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm {\n    display: block !important;\n  }\n\n  table.visible-sm {\n    display: table;\n  }\n\n  tr.visible-sm {\n    display: table-row !important;\n  }\n\n  th.visible-sm,\n  td.visible-sm {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-block {\n    display: block !important;\n  }\n}\n\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-inline {\n    display: inline !important;\n  }\n}\n\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-inline-block {\n    display: inline-block !important;\n  }\n}\n\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md {\n    display: block !important;\n  }\n\n  table.visible-md {\n    display: table;\n  }\n\n  tr.visible-md {\n    display: table-row !important;\n  }\n\n  th.visible-md,\n  td.visible-md {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-block {\n    display: block !important;\n  }\n}\n\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-inline {\n    display: inline !important;\n  }\n}\n\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-inline-block {\n    display: inline-block !important;\n  }\n}\n\n@media (min-width: 1200px) {\n  .visible-lg {\n    display: block !important;\n  }\n\n  table.visible-lg {\n    display: table;\n  }\n\n  tr.visible-lg {\n    display: table-row !important;\n  }\n\n  th.visible-lg,\n  td.visible-lg {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg-block {\n    display: block !important;\n  }\n}\n\n@media (min-width: 1200px) {\n  .visible-lg-inline {\n    display: inline !important;\n  }\n}\n\n@media (min-width: 1200px) {\n  .visible-lg-inline-block {\n    display: inline-block !important;\n  }\n}\n\n@media (max-width: 767px) {\n  .hidden-xs {\n    display: none !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .hidden-sm {\n    display: none !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .hidden-md {\n    display: none !important;\n  }\n}\n@media (min-width: 1200px) {\n  .hidden-lg {\n    display: none !important;\n  }\n}\n.visible-print {\n  display: none !important;\n}\n\n@media print {\n  .visible-print {\n    display: block !important;\n  }\n\n  table.visible-print {\n    display: table;\n  }\n\n  tr.visible-print {\n    display: table-row !important;\n  }\n\n  th.visible-print,\n  td.visible-print {\n    display: table-cell !important;\n  }\n}\n.visible-print-block {\n  display: none !important;\n}\n@media print {\n  .visible-print-block {\n    display: block !important;\n  }\n}\n\n.visible-print-inline {\n  display: none !important;\n}\n@media print {\n  .visible-print-inline {\n    display: inline !important;\n  }\n}\n\n.visible-print-inline-block {\n  display: none !important;\n}\n@media print {\n  .visible-print-inline-block {\n    display: inline-block !important;\n  }\n}\n\n@media print {\n  .hidden-print {\n    display: none !important;\n  }\n}\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, 0.2);\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.btn-default:active, .btn-default.active,\n.btn-primary:active,\n.btn-primary.active,\n.btn-success:active,\n.btn-success.active,\n.btn-info:active,\n.btn-info.active,\n.btn-warning:active,\n.btn-warning.active,\n.btn-danger:active,\n.btn-danger.active {\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n\n.btn:active, .btn.active {\n  background-image: none;\n}\n\n.btn-default {\n  background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);\n  background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);\n  background-image: linear-gradient(to bottom, #ffffff 0%, #e0e0e0 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFE0E0E0', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #dbdbdb;\n  text-shadow: 0 1px 0 #fff;\n  border-color: #ccc;\n}\n.btn-default:hover, .btn-default:focus {\n  background-color: #e0e0e0;\n  background-position: 0 -15px;\n}\n.btn-default:active, .btn-default.active {\n  background-color: #e0e0e0;\n  border-color: #dbdbdb;\n}\n.btn-default:disabled, .btn-default[disabled] {\n  background-color: #e0e0e0;\n  background-image: none;\n}\n\n.btn-primary {\n  background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%);\n  background-image: -o-linear-gradient(top, #428bca 0%, #2d6ca2 100%);\n  background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF428BCA', endColorstr='#FF2D6CA2', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #2b669a;\n}\n.btn-primary:hover, .btn-primary:focus {\n  background-color: #2d6ca2;\n  background-position: 0 -15px;\n}\n.btn-primary:active, .btn-primary.active {\n  background-color: #2d6ca2;\n  border-color: #2b669a;\n}\n.btn-primary:disabled, .btn-primary[disabled] {\n  background-color: #2d6ca2;\n  background-image: none;\n}\n\n.btn-success {\n  background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);\n  background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);\n  background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF5CB85C', endColorstr='#FF419641', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #3e8f3e;\n}\n.btn-success:hover, .btn-success:focus {\n  background-color: #419641;\n  background-position: 0 -15px;\n}\n.btn-success:active, .btn-success.active {\n  background-color: #419641;\n  border-color: #3e8f3e;\n}\n.btn-success:disabled, .btn-success[disabled] {\n  background-color: #419641;\n  background-image: none;\n}\n\n.btn-info {\n  background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n  background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n  background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF5BC0DE', endColorstr='#FF2AABD2', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #28a4c9;\n}\n.btn-info:hover, .btn-info:focus {\n  background-color: #2aabd2;\n  background-position: 0 -15px;\n}\n.btn-info:active, .btn-info.active {\n  background-color: #2aabd2;\n  border-color: #28a4c9;\n}\n.btn-info:disabled, .btn-info[disabled] {\n  background-color: #2aabd2;\n  background-image: none;\n}\n\n.btn-warning {\n  background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n  background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n  background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFF0AD4E', endColorstr='#FFEB9316', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #e38d13;\n}\n.btn-warning:hover, .btn-warning:focus {\n  background-color: #eb9316;\n  background-position: 0 -15px;\n}\n.btn-warning:active, .btn-warning.active {\n  background-color: #eb9316;\n  border-color: #e38d13;\n}\n.btn-warning:disabled, .btn-warning[disabled] {\n  background-color: #eb9316;\n  background-image: none;\n}\n\n.btn-danger {\n  background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n  background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n  background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFD9534F', endColorstr='#FFC12E2A', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #b92c28;\n}\n.btn-danger:hover, .btn-danger:focus {\n  background-color: #c12e2a;\n  background-position: 0 -15px;\n}\n.btn-danger:active, .btn-danger.active {\n  background-color: #c12e2a;\n  border-color: #b92c28;\n}\n.btn-danger:disabled, .btn-danger[disabled] {\n  background-color: #c12e2a;\n  background-image: none;\n}\n\n.thumbnail,\n.img-thumbnail {\n  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFF5F5F5', endColorstr='#FFE8E8E8', GradientType=0);\n  background-color: #e8e8e8;\n}\n\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n  background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);\n  background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%);\n  background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF428BCA', endColorstr='#FF357EBD', GradientType=0);\n  background-color: #357ebd;\n}\n\n.navbar-default {\n  background-image: -webkit-linear-gradient(top, white 0%, #f8f8f8 100%);\n  background-image: -o-linear-gradient(top, white 0%, #f8f8f8 100%);\n  background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFF8F8F8', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n}\n.navbar-default .navbar-nav > .active > a {\n  background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%);\n  background-image: -o-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%);\n  background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEBEBEB', endColorstr='#FFF3F3F3', GradientType=0);\n  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n}\n\n.navbar-brand,\n.navbar-nav > li > a {\n  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);\n}\n\n.navbar-inverse {\n  background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);\n  background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%);\n  background-image: linear-gradient(to bottom, #3c3c3c 0%, #222222 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF3C3C3C', endColorstr='#FF222222', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n}\n.navbar-inverse .navbar-nav > .active > a {\n  background-image: -webkit-linear-gradient(top, #222 0%, #282828 100%);\n  background-image: -o-linear-gradient(top, #222 0%, #282828 100%);\n  background-image: linear-gradient(to bottom, #222222 0%, #282828 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF222222', endColorstr='#FF282828', GradientType=0);\n  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n  box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n}\n.navbar-inverse .navbar-brand,\n.navbar-inverse .navbar-nav > li > a {\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  border-radius: 0;\n}\n\n.alert {\n  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.alert-success {\n  background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n  background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n  background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFDFF0D8', endColorstr='#FFC8E5BC', GradientType=0);\n  border-color: #b2dba1;\n}\n\n.alert-info {\n  background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n  background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n  background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFD9EDF7', endColorstr='#FFB9DEF0', GradientType=0);\n  border-color: #9acfea;\n}\n\n.alert-warning {\n  background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n  background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n  background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFCF8E3', endColorstr='#FFF8EFC0', GradientType=0);\n  border-color: #f5e79e;\n}\n\n.alert-danger {\n  background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n  background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n  background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFF2DEDE', endColorstr='#FFE7C3C3', GradientType=0);\n  border-color: #dca7a7;\n}\n\n.progress {\n  background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n  background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n  background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEBEBEB', endColorstr='#FFF5F5F5', GradientType=0);\n}\n\n.progress-bar {\n  background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%);\n  background-image: -o-linear-gradient(top, #428bca 0%, #3071a9 100%);\n  background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF428BCA', endColorstr='#FF3071A9', GradientType=0);\n}\n\n.progress-bar-success {\n  background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n  background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n  background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF5CB85C', endColorstr='#FF449D44', GradientType=0);\n}\n\n.progress-bar-info {\n  background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n  background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n  background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF5BC0DE', endColorstr='#FF31B0D5', GradientType=0);\n}\n\n.progress-bar-warning {\n  background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n  background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n  background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFF0AD4E', endColorstr='#FFEC971F', GradientType=0);\n}\n\n.progress-bar-danger {\n  background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n  background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n  background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFD9534F', endColorstr='#FFC9302C', GradientType=0);\n}\n\n.progress-bar-striped {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, rgba(0, 0, 0, 0) 25%, rgba(0, 0, 0, 0) 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, rgba(0, 0, 0, 0) 75%, rgba(0, 0, 0, 0));\n}\n\n.list-group {\n  border-radius: 4px;\n  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n  text-shadow: 0 -1px 0 #3071a9;\n  background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%);\n  background-image: -o-linear-gradient(top, #428bca 0%, #3278b3 100%);\n  background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF428BCA', endColorstr='#FF3278B3', GradientType=0);\n  border-color: #3278b3;\n}\n\n.panel {\n  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.panel-default > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFF5F5F5', endColorstr='#FFE8E8E8', GradientType=0);\n}\n\n.panel-primary > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);\n  background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%);\n  background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF428BCA', endColorstr='#FF357EBD', GradientType=0);\n}\n\n.panel-success > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n  background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n  background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFDFF0D8', endColorstr='#FFD0E9C6', GradientType=0);\n}\n\n.panel-info > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n  background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n  background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFD9EDF7', endColorstr='#FFC4E3F3', GradientType=0);\n}\n\n.panel-warning > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n  background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n  background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFCF8E3', endColorstr='#FFFAF2CC', GradientType=0);\n}\n\n.panel-danger > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n  background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n  background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFF2DEDE', endColorstr='#FFEBCCCC', GradientType=0);\n}\n\n.well {\n  background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n  background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n  background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFE8E8E8', endColorstr='#FFF5F5F5', GradientType=0);\n  border-color: gainsboro;\n  -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n}\n\n.thumbnail-list li div.selection-show {\n  position: absolute;\n  border: 1px dashed red;\n  display: none;\n  pointer-events: none;\n}\n\n/* selections */\n.repeat-lassos-group {\n  position: absolute;\n  right: -185px;\n  bottom: -35px;\n}\n\n/* rectangularSelector.js classes */\n.selection-box, .table-region {\n  position: absolute;\n  border: 1px dashed rgba(255, 87, 0, 0.8);\n  background: rgba(255, 87, 0, 0.2);\n  box-sizing: border-box;\n}\n.selection-box:hover, .table-region:hover {\n  cursor: pointer;\n}\n\n.selection-box {\n  z-index: 42;\n  width: 0;\n  height: 0;\n  visibility: hidden;\n}\n\n.table-region {\n  top: 0;\n  left: 0;\n  z-index: 21;\n}\n\ndiv.table-region .resize-handle {\n  position: absolute;\n}\n\ndiv.table-region .n-border {\n  width: calc(100% - 10px);\n  top: -5px;\n  left: 5px;\n  height: 10px;\n}\n\ndiv.table-region .s-border {\n  width: calc(100% - 10px);\n  bottom: -5px;\n  left: 5px;\n  height: 10px;\n}\n\ndiv.table-region .w-border {\n  height: calc(100% - 10px);\n  left: -5px;\n  top: 5px;\n  width: 10px;\n}\n\ndiv.table-region .e-border {\n  height: calc(100% - 10px);\n  top: 5px;\n  right: -5px;\n  width: 10px;\n}\n\ndiv.table-region .nw-border {\n  width: 10px;\n  height: 10px;\n  top: -5px;\n  left: -5px;\n}\n\ndiv.table-region .ne-border {\n  width: 10px;\n  height: 10px;\n  top: -5px;\n  right: -5px;\n}\n\ndiv.table-region .sw-border {\n  width: 10px;\n  height: 10px;\n  bottom: -5px;\n  left: -5px;\n}\n\ndiv.table-region .se-border {\n  width: 10px;\n  height: 10px;\n  bottom: -5px;\n  right: -5px;\n}\n\ndiv.table-region .n-border:hover {\n  cursor: n-resize;\n}\n\ndiv.table-region .nw-border:hover {\n  cursor: nw-resize;\n}\n\ndiv.table-region .ne-border:hover {\n  cursor: ne-resize;\n}\n\ndiv.table-region .s-border:hover {\n  cursor: s-resize;\n}\n\ndiv.table-region .sw-border:hover {\n  cursor: sw-resize;\n}\n\ndiv.table-region .se-border:hover {\n  cursor: se-resize;\n}\n\ndiv.table-region .w-border:hover {\n  cursor: w-resize;\n}\n\ndiv.table-region .e-border:hover {\n  cursor: e-resize;\n}\n\ndiv.table-region button[name=close] {\n  font-weight: bold;\n  border: 0;\n  background-color: transparent;\n  padding: 0;\n  font-size: 20px;\n  position: relative;\n  top: -25px;\n  left: 100%;\n  margin-left: 5px;\n}\n\ndiv.table-region button[name=close]:hover {\n  color: red;\n}\n\n@font-face {\n  font-family: 'Glyphicons Halflings';\n  src: url(\"glyphicons-halflings-regular.eot\");\n  src: url(\"../fonts/bootstrap/glyphicons-halflings-regular.eot?#iefix\") format(\"embedded-opentype\"), url(\"../fonts/bootstrap/glyphicons-halflings-regular.woff\") format(\"woff\"), url(\"../fonts/bootstrap/glyphicons-halflings-regular.ttf\") format(\"truetype\"), url(\"../fonts/bootstrap/glyphicons-halflings-regular.svg#webfont\") format(\"svg\");\n}\nbody {\n  padding-top: 70px;\n}\n\n.jumbotron h1 {\n  font-size: 2em;\n}\n.jumbotron h2, .jumbotron h3, .jumbotron h4, .jumbotron h5, .jumbotron h6 {\n  font-size: 1.3em;\n}\n.jumbotron p {\n  font-size: 1.3em;\n}\n\n.navbar-fixed-top .container {\n  width: 95%;\n  margin: 0 auto;\n}\n\n#navbar .active {\n  font-weight: 500;\n  color: #333333;\n}\n\n.navbar-default a.navbar-brand {\n  padding-left: 30px;\n  position: relative;\n  font-weight: bold;\n  color: black;\n}\n.navbar-default a.navbar-brand::before {\n  position: absolute;\n  content: \"\";\n  display: block;\n  background-image: url(\"../img/logo.png\");\n  background-repeat: no-repeat;\n  background-size: 25px 30px;\n  width: 25px;\n  height: 30px;\n  left: 0;\n  top: 10px;\n}\n\n.btn-file {\n  position: relative;\n  overflow: hidden;\n}\n\n.btn-file input[type=file] {\n  position: absolute;\n  top: 0;\n  right: 0;\n  min-width: 100%;\n  min-height: 100%;\n  font-size: 100px;\n  text-align: right;\n  filter: alpha(opacity=0);\n  opacity: 0;\n  outline: none;\n  background: white;\n  cursor: inherit;\n  display: block;\n}\n\n.form-inline .input-group > .form-control, .navbar-form .input-group > .form-control {\n  background: white;\n  width: 500px;\n}\n\nform {\n  margin-bottom: 3em;\n}\n\n#file-list-container {\n  max-height: 500px;\n  overflow-y: scroll;\n}\n#file-list-container .file-list thead tr th {\n  text-align: center;\n  cursor: pointer;\n  position: relative;\n  border-right: 1px solid #ddd;\n  padding-right: 20px;\n}\n#file-list-container .file-list thead tr th::before, #file-list-container .file-list thead tr th::after {\n  text-align: right;\n  width: 11px;\n  color: #ddd;\n  position: absolute;\n  display: block;\n  font-family: 'Glyphicons Halflings';\n  font-size: .8em;\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#file-list-container .file-list thead tr th::before {\n  content: \"\\e113\";\n  right: 3px;\n  top: 6px;\n}\n#file-list-container .file-list thead tr th::after {\n  content: \"\\e114\";\n  right: 4px;\n  bottom: 6px;\n}\n#file-list-container .file-list thead tr th.headerSortUp::before {\n  color: #777777 !important;\n}\n#file-list-container .file-list thead tr th.headerSortDown:after {\n  color: #777777 !important;\n}\n#file-list-container .file-list thead tr th:first-of-type {\n  text-align: left;\n}\n#file-list-container .file-list thead tr th:nth-child(n+5) {\n  cursor: default;\n  padding-right: 8px;\n}\n#file-list-container .file-list thead tr th:nth-child(n+5)::before, #file-list-container .file-list thead tr th:nth-child(n+5)::after {\n  content: \"\";\n  display: none;\n  position: relative;\n}\n#file-list-container .file-list tbody tr {\n  background: white;\n}\n#file-list-container .file-list tbody tr:hover {\n  background: #d9edf7;\n}\n#file-list-container .file-list tbody tr td {\n  line-height: 2.25;\n  text-align: center;\n}\n#file-list-container .file-list tbody tr td:first-of-type {\n  font-weight: bold;\n  text-align: left;\n}\n#file-list-container .file-list tbody tr td a {\n  color: #333;\n}\n\n.glyphicon-remove {\n  color: #777777;\n}\n.glyphicon-remove:hover {\n  color: #d9534f;\n}\n\n#sidebar {\n  background: #eeeeee;\n  width: 195px;\n  padding: 1em 0 0;\n  height: calc(100% - 51px);\n  text-align: center;\n  overflow-y: scroll;\n  overflow-x: hidden;\n  position: fixed;\n  left: 0;\n  top: 51px;\n  z-index: 2;\n  -webkit-box-shadow: inset -0.25em 0 0.5em -0.25em rgba(0, 0, 0, 0.1);\n  box-shadow: inset -0.25em 0 0.5em -0.25em rgba(0, 0, 0, 0.1);\n}\n#sidebar h5 {\n  border-top: 1px solid #777777;\n  padding-top: 1em;\n  margin-top: 1em;\n}\n#sidebar .btn-group button {\n  width: 83px;\n  margin-bottom: 10px;\n}\n#sidebar p {\n  font-size: .9em;\n}\n#sidebar .thumbnail-list {\n  padding-left: 0px;\n}\n#sidebar .thumbnail-list .page {\n  margin: 0 auto 1.25em;\n  display: block;\n  width: 90%;\n  padding: 1em .5em .5em 1em;\n  position: relative;\n}\n#sidebar .thumbnail-list .page img {\n  display: block;\n  width: 100%;\n}\n#sidebar .thumbnail-list .page p {\n  margin-top: .25em;\n  color: #555555;\n  line-height: 1;\n}\n#sidebar .thumbnail-list .page:hover img {\n  cursor: pointer;\n  -webkit-box-shadow: 0 0 0 0.1em rgba(0, 0, 0, 0.1);\n  box-shadow: 0 0 0 0.1em rgba(0, 0, 0, 0.1);\n}\n#sidebar .thumbnail-list .page.active img {\n  -webkit-box-shadow: 0 0 0 0.1em #5bc0de;\n  box-shadow: 0 0 0 0.1em #5bc0de;\n}\n#sidebar .thumbnail-list .page .remove {\n  position: absolute;\n  left: -.25em;\n  top: 1em;\n  height: 1em;\n  display: block;\n  line-height: 1;\n  font-size: 1em;\n}\n#sidebar .thumbnail-list .page .remove:hover {\n  cursor: pointer;\n}\n\n#control-panel {\n  position: fixed;\n  top: 50px;\n  left: 195px;\n  width: calc(100% - 200px);\n  z-index: 101;\n  /* gotta be >100, which is the max z-index for selections */\n  background: #d9edf7;\n  padding: 1em;\n  -webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.075);\n  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.075);\n}\n#control-panel button {\n  margin-right: 1.25em;\n}\n#control-panel .filename {\n  display: inline-block;\n  margin-right: 20px;\n  max-width: 270px;\n  white-space: nowrap;\n  overflow: hidden;\n  text-overflow: ellipsis;\n}\n#control-panel span.filename {\n  vertical-align: middle;\n}\n#control-panel #template-dropdown-container ul {\n  padding-left: 20px;\n}\n#control-panel #template-dropdown-container button {\n  padding-left: 0px;\n}\n#control-panel #template-dropdown-container ul:first-of-type {\n  margin-bottom: 0px;\n}\n#control-panel #template-dropdown-container li a {\n  cursor: pointer;\n  color: #333;\n}\n#control-panel #template-dropdown-templates-list-container li a {\n  cursor: pointer;\n  color: #333;\n}\n\n#notifications-approval-clicky{\n  width: 100%;\n  padding: 1em 3em;\n  position: fixed;\n  bottom: 0;\n  background: #FFFFE0;\n  font-size: 14px;\n}\n#notifications-approval-clicky #notifications-approval-close {\n  position: absolute;\n  right: 0;\n  top: 0;\n}\n\n#main-pane {\n  background: #777777;\n  padding: 4.25em 2em 2em 2em;\n  margin-left: 195px;\n  height: 100%;\n  width: calc(100% - 200px);\n  z-index: 1;\n}\n#main-pane .pdf-page {\n  position: relative;\n}\n#main-pane .pdf-page .page-number {\n  position: absolute;\n}\n#main-pane .page {\n  width: 100%;\n  max-width: 800px;\n  min-width: 560px;\n  -webkit-box-shadow: 0 0 2em rgba(0, 0, 0, 0.4);\n  box-shadow: 0 0 2em rgba(0, 0, 0, 0.4);\n  position: relative;\n  margin: 0 auto;\n}\n#main-pane .page img {\n  margin: 2em 0;\n  display: block;\n  width: 100%;\n  max-width: 800px;\n  min-width: 560px;\n  user-select: none;\n  -moz-user-select: none;\n  -webkit-user-select: none;\n  -ms-user-select: none;\n}\n#main-pane .page img:hover {\n  cursor: crosshair;\n}\n#main-pane .selection-box, #main-pane .table-region {\n  border: 3px dashed rgba(224, 1, 1, 0.6);\n  background: rgba(224, 1, 1, 0.2);\n}\n#main-pane .selection-box .selection-panel, #main-pane .table-region .selection-panel {\n  display: none;\n  position: absolute;\n  bottom: -2.8em;\n  left: 0;\n  min-width: 320px;\n}\n#main-pane .selection-box .selection-panel button:hover, #main-pane .table-region .selection-panel button:hover {\n  cursor: pointer;\n}\n#main-pane .selection-box:hover, #main-pane .table-region:hover {\n  cursor: move;\n}\n#main-pane .selection-box:hover .selection-panel, #main-pane .table-region:hover .selection-panel {\n  display: block;\n}\n\nbody.page-selections {\n  padding-top: 50px;\n  background: #777777;\n}\nbody.page-selections #main-pane {\n  background: #777777;\n}\n\nbody.page-export {\n  padding-top: 50px;\n  background: white;\n}\nbody.page-export #sidebar {\n  text-align: left;\n  padding: .5em;\n}\nbody.page-export #sidebar .lattice.glyphicon {\n  color: #ededed;\n  background: #666;\n  text-shadow: none;\n  border: solid #666;\n  border-width: 0 0 1px 1px;\n}\nbody.page-export #main-pane {\n  background: white;\n  padding-top: 5.5em;\n}\nbody.page-export #main-pane #control-panel form {\n  display: inline-block;\n  margin-bottom: 0;\n}\nbody.page-export #main-pane #control-panel form .form-control {\n  width: 100px;\n  margin-right: 1em;\n  display: inline-block;\n}\nbody.page-export #main-pane #control-panel form .form-control.format {\n  width: 130px;\n}\nbody.page-export #main-pane #control-panel form #copy-csv-to-clipboard {\n  min-width: 140px;\n}\nbody.page-export #main-pane table {\n  margin-top: 2em;\n}\n\n.jumbotron.about p {\n  font-size: 1.1em;\n}\n\ndiv.spinner {\n  top: 10px !important;\n}\n\n#progress-container h5 {\n  display: inline-block;\n  font-size: 1.1em;\n  font-weight: bold;\n}\n\n#progress-container #message {\n  color: #aaa;\n}\n\n.autodetect-in-progress .glyphicon-refresh,\n#download-data.download-in-progress .glyphicon-refresh {\n  animation: 4s linear 0s normal none infinite running spin;\n  display: inline-block;\n}\n\n@-moz-keyframes spin {\n  0% {\n    -moz-transform: rotate(0deg);\n  }\n  100% {\n    -moz-transform: rotate(359deg);\n  }\n}\n@-webkit-keyframes spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n  }\n}\n@-o-keyframes spin {\n  0% {\n    -o-transform: rotate(0deg);\n  }\n  100% {\n    -o-transform: rotate(359deg);\n  }\n}\n@keyframes spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n    transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n    transform: rotate(359deg);\n  }\n}\n.autodetect-in-progress .glyphicon-flash {\n  display: none;\n}\n\n.autodetect-finished .glyphicon-flash {\n  display: inline;\n}\n\n.autodetect-finished .glyphicon-refresh {\n  display: none;\n}\n\n#download-data.download-in-progress .glyphicon-download {\n  display: none;\n}\n#download-data .glyphicon-download {\n  display: inline;\n}\n#download-data .glyphicon-refresh {\n  display: none;\n}\n\n.flash {\n  -moz-animation: flash 2s ease-out;\n  -moz-animation-iteration-count: 1;\n  -webkit-animation: flash 2s ease-out;\n  -webkit-animation-iteration-count: 1;\n  -ms-animation: flash 2s ease-out;\n  -ms-animation-iteration-count: 1;\n}\n\n@-webkit-keyframes flash {\n  0% {\n    background-color: none;\n  }\n  50% {\n    background-color: #fbf8b2;\n  }\n  100% {\n    background-color: none;\n  }\n}\n@-moz-keyframes flash {\n  0% {\n    background-color: none;\n  }\n  50% {\n    background-color: #fbf8b2;\n  }\n  100% {\n    background-color: none;\n  }\n}\n@-ms-keyframes flash {\n  0% {\n    background-color: none;\n  }\n  50% {\n    background-color: #fbf8b2;\n  }\n  100% {\n    background-color: none;\n  }\n}\n#loading {\n  padding-left: 30px;\n}\n#loading #spinner {\n  position: relative;\n  top: 6px;\n  margin-right: 5px;\n}\n"
  },
  {
    "path": "webapp/static/js/debug_pdf_view.js",
    "content": "Tabula.DebugPDFView = {\n    colors: ['#f00', '#0f0', '#00f', '#ffff00', '#FF00FF'],\n    debugRulings: function(image, render, clean, show_intersections) {\n        image = $(image);\n        var imagePos = image.offset();\n        var newCanvas =  $('<canvas/>',{'class':'debug-canvas'})\n            .attr('width', image.width())\n            .attr('height', image.height())\n            .css('top', imagePos.top + 'px')\n            .css('left', imagePos.left + 'px');\n        $('body').append(newCanvas);\n\n        var pdf_rotation = parseInt($(image).data('rotation'));\n        var original_pdf_width = parseInt($(image).data('original-width'));\n        var original_pdf_height = parseInt($(image).data('original-height'));\n        var thumb_width = $(image).width();\n\n        var scale = thumb_width / (Math.abs(pdf_rotation) == 90 ? original_pdf_height : original_pdf_width);\n\n        var lq = $.extend(this.lastQuery,\n                          {\n                              pdf_page_width: original_pdf_width,\n                              render_page: render === true,\n                              clean_rulings: clean === true,\n                              show_intersections: show_intersections === true\n                          });\n\n        $.get('/debug/' + PDF_ID + '/rulings',\n              lq,\n              _.bind(function(data) {\n                  $.each(data.rulings, _.bind(function(i, ruling) {\n                      $(\"canvas\").drawLine({\n                          strokeStyle: this.colors[i % this.colors.length],\n                          strokeWidth: 1,\n                          x1: ruling[0] * scale, y1: ruling[1] * scale,\n                          x2: ruling[2] * scale, y2: ruling[3] * scale\n                      });\n                  }, this));\n\n                  $.each(data.intersections, _.bind(function(i, intersection) {\n                      $(\"canvas\").drawEllipse({\n                          fillStyle: this.colors[i % this.colors.length],\n                          width: 5, height: 5,\n                          x: intersection[0] * scale,\n                          y: intersection[1] * scale\n                      });\n                  }, this));\n              }, this));\n    },\n\n    _debugRectangularShapes: function(image, url) {\n      image = $(image);\n      var imagePos = image.offset();\n      var newCanvas =  $('<canvas/>',{'class':'debug-canvas'})\n          .attr('width', image.width())\n          .attr('height', image.height())\n          .css('top', imagePos.top + 'px')\n          .css('left', imagePos.left + 'px');\n      $('body').append(newCanvas);\n\n      var thumb_width = $(image).width();\n      var thumb_height = $(image).height();\n      var original_pdf_width = parseInt($(image).data('original-width'));\n      var original_pdf_height = parseInt($(image).data('original-height'));\n      var pdf_rotation = parseInt($(image).data('rotation'));\n\n      var scale = thumb_width / (Math.abs(pdf_rotation) == 90 ? original_pdf_height : original_pdf_width);\n\n      $.get(url,\n            this.lastQuery,\n            _.bind(function(data) {\n                $.each(data, _.bind(function(i, row) {\n                    $(\"canvas\").drawRect({\n                        strokeStyle: this.colors[i % this.colors.length],\n                        strokeWidth: 1,\n                        x: row.left * scale, y: row.top * scale,\n                        width: row.width * scale,\n                        height: row.height * scale,\n                        fromCenter: false\n                    });\n                }, this));\n            }, this));\n\n    },\n\n    debugCharacters: function(image) {\n      return this._debugRectangularShapes(image, '/debug/' + PDF_ID + '/characters');\n    },\n\n    debugClippingPaths: function(image) {\n      return this._debugRectangularShapes(image, '/debug/' + PDF_ID + '/clipping_paths');\n    },\n\n    debugColumns: function(image) {\n      image = $(image);\n      var imagePos = image.offset();\n      var newCanvas =  $('<canvas/>',{'class':'debug-canvas'})\n          .attr('width', image.width())\n          .attr('height', image.height())\n          .css('top', imagePos.top + 'px')\n          .css('left', imagePos.left + 'px');\n      $('body').append(newCanvas);\n\n      var thumb_width = $(image).width();\n      var thumb_height = $(image).height();\n      var original_pdf_width = parseInt($(image).data('original-width'));\n      var original_pdf_height = parseInt($(image).data('original-height'));\n      var pdf_rotation = parseInt($(image).data('rotation'));\n\n      var scale = thumb_width / (Math.abs(pdf_rotation) == 90 ? original_pdf_height : original_pdf_width);\n\n      var list_of_coords = JSON.parse(this.lastQuery.coords);\n\n      Tabula.pdf_view.query.doQuery({\n        success: _.bind(function(data) {\n                   var colors = this.colors;\n                   $.each(data[0].vertical_separators, function(i, vert) {\n                     newCanvas.drawLine({\n                       strokeStyle: colors[i % colors.length],\n                       strokeWidth: 1,\n                       x1: vert * scale, y1: list_of_coords[0].y1 * scale,\n                       x2: vert * scale, y2: list_of_coords[0].y2 * scale\n                     });\n                   });\n                 }, this)});\n\n    },\n\n    debugCoordsToTabula: function() {\n        var coords = eval(this.lastQuery.coords)[0];\n        return [coords.y1, coords.x1, coords.y2, coords.x2].join(',');\n    },\n\n    debugTextChunks: function(image) {\n      return this._debugRectangularShapes(image, '/debug/' + PDF_ID + '/text_chunks');\n    },\n})"
  },
  {
    "path": "webapp/static/js/library.js",
    "content": "Tabula = window.Tabula || {};\nvar base_uri = $('base').attr(\"href\");\n\nTabula.FileUpload = Backbone.Model.extend({\n  // isOneOfMultiple:\n  // uploadTime\n  // uploadOrder\n  initialize: function(){\n    this.set({\n      message: 'waiting to be processed...',\n      pct_complete: 0,\n      warnings: []\n    });\n  },\n\n  checkStatus: function() {\n    if(typeof this.get('file_id') == 'undefined' && typeof !this.get('upload_id') == 'undefined'){\n      this.pct_complete = 1;\n      this.message = \"waiting to be processed...\"\n    }else{\n      $.ajax({\n          dataType: 'json',\n          url: (base_uri || '/') + 'queue/'+this.get('upload_id')+'/json?file_id=' + this.get('file_id'),\n          success: _.bind(function(data, status, xhr) {\n            if( (data.message.length && data.message != \"complete\") || data.pct_complete == 100 ){\n              this.set('message',  data.message);\n            } else if(data.pct_complete > 1) {\n              this.set('message', 'processing');\n            }\n\n            this.set('pct_complete', data.pct_complete);\n            this.set('warnings', data.warnings);\n\n            if (data.status == \"error\" && data.error_type == \"unknown\") {\n                // window.location.reload(true);\n            } else if (data.status == \"error\" && data.error_type == \"no-text\") {\n                console.log('no text');\n                window.clearTimeout(this.timer);\n\n                // resets upload/input form\n                $('form#upload').find('button').removeAttr('disabled');\n                $('form#upload')[0].reset();\n\n                //TODO: something prettier.\n                alert(\"Sorry, your PDF file is image-based; it does not have any embedded text. It might have been scanned from paper... Tabula isn't able to extract any data from image-based PDFs. Click the Help button for more information.\");\n            } else if(data.pct_complete < 100) {\n                this.timer = setTimeout(_.bind(this.checkStatus, this), 1000);\n            } else {\n              this.collection.remove(this);\n              Tabula.library.files_collection.fetch();\n            }\n          }, this),\n          error: function(xhr, status, err) {\n              console.log('err', err); //TODO:\n          }\n      });\n    }\n  },\n\n});\n\n// does flash work?\n// clear the input\n\nTabula.FileUploadsCollection = Backbone.Collection.extend({\n  model: Tabula.FileUpload,\n  comparator: function(i){ return -i.get('uploadTime') - i.get('uploadOrder')},\n})\n\nTabula.UploadedFile = Backbone.Model.extend({\n  size: null,\n  page_count: null,\n  initialize: function(){\n    this.set('size', this.get('size') || null);\n    this.set('page_count', this.get('page_count') || null)\n  }\n});\n\nTabula.UploadedFilesCollection = Backbone.Collection.extend({\n    model: Tabula.UploadedFile,\n    url: function(){ return 'documents'+ '?' + Number(new Date()).toString() },\n    comparator: function(i){ return -i.get('time')},\n    parse: function(pdfs){\n      _(pdfs).each(function(i){\n        if(!i.original_filename){\n          i.original_filename = i.file;\n        }\n      });\n      // if it's still being processed, don't enter it into the library.\n      pdfs = _(pdfs).reject(_.bind(function(uploaded_file){\n        var in_progress = Tabula.library && Tabula.library.uploads_collection.findWhere({file_id: uploaded_file.id});\n        return in_progress\n      }, this));\n      return pdfs;\n    }\n});\n\n\nTabula.UploadedFileView = Backbone.View.extend({\n  tagName: 'tr',\n  className: 'uploaded-file',\n  events: {\n    'click .delete-pdf': 'deletePDF'\n  },\n  template: _.template( $('#uploaded-file-template').html().replace(/nestedscript/g, 'script')),\n  initialize: function(){\n    _.bindAll(this, 'render', 'deletePDF');\n  },\n  render: function(){\n    this.$el.append(this.template(this.model.attributes));\n    this.$el.addClass('file-id-' + this.model.get('id')); // more efficient lookups than data-attr\n    this.$el.data('id', this.model.get('id')); //more cleanly accesse than a class\n    return this;\n  },\n  deletePDF: function(e) {\n    var btn = $(e.currentTarget);\n    var tr = btn.parents('tr');\n\n    if (!confirm('Delete file \"'+btn.data('filename')+'\"?')) return;\n    var pdf_id = btn.data('pdfid');\n\n    $.post((base_uri || '/') + 'pdf/' + pdf_id,\n          { _method: 'delete' },\n          function() {\n            tr.fadeOut(200, function() { $(this).remove(); });\n          });\n    },\n})\n\nTabula.ProgressBars = Backbone.View.extend({\n  template: _.template( $('#progress-bars-template').html().replace(/nestedscript/g, 'script')),\n  initialize: function(stuff){\n    _.extend(this, stuff); //  in-place.\n    this.listenTo(this.uploads_collection, 'remove', this.render);\n  },\n  render: function(){\n    if(this.uploads_collection.size() > 0){\n      this.in_progress = false;\n      if(!$.trim(this.$el.html())) this.$el.html(this.template({}))\n    }else if(!this.in_progress){\n      //TODO: this belongs in Library, technically, but we don't go around rerendering that, so here it is for now.\n      $('form#upload').find('button').removeAttr('disabled');\n      $('form#upload')[0].reset();\n    }\n    return this;\n  }\n});\n\nTabula.Library = Backbone.View.extend({\n    events: {\n        \"submit form#upload\": 'uploadPDF',\n    },\n    template: _.template( $('#uploader-template').html().replace(/nestedscript/g, 'script')),\n    initialize: function(){\n      _.bindAll(this, 'uploadPDF', 'render', 'renderFileLibrary');\n      this.files_collection = new Tabula.UploadedFilesCollection([]);\n      this.files_collection.fetch({silent: true, complete: _.bind(function(){ this.render(); }, this) });\n      \n      this.listenTo(this.files_collection, 'add', this.renderFileLibrary);\n      this.uploads_collection = new Tabula.FileUploadsCollection([]);\n\n      this.listenTo(Tabula.notification, 'change', this.renderNotification);\n      this.listenTo(Tabula.new_version, 'change', this.renderVersion);\n    },\n    renderNotification: function(){\n      if(_.isEmpty(Tabula.notification.attributes)) return;\n      $('#notification-alert').html(_.template($('#notification-template').html().replace(/nestedscript/g, 'script'))({\n        notification: Tabula.notification.attributes,\n        api_version: Tabula.api_version\n      })).show();\n    },\n    renderVersion: function(){\n      if(_.isEmpty(Tabula.new_version.attributes)) return;\n      console.log('render new version');\n      $('#new-version-alert').html(_.template($('#new-version-template').html().replace(/nestedscript/g, 'script'))({\n        new_release: Tabula.new_version.attributes,\n        api_version: Tabula.api_version\n      })).show();\n    },\n    uploadPDF: function(e){\n      $(e.currentTarget).find('button').attr('disabled', 'disabled');\n      this.progress_bars = new Tabula.ProgressBars({el: '#progress-container', uploads_collection: this.uploads_collection });\n      this.progress_bars.in_progress = true;\n      this.progress_bars.render();\n\n      var files_list = $(e.currentTarget).find('#file')[0].files\n      _(files_list).each(_.bind(function(file, index){\n        //TODO: the model should get the data, then fire an event that the view listens for, to rerender\n        var file_upload = new Tabula.FileUpload({\n          collection: this.uploads_collection,\n          filename: file.name,\n          uploadTime: new Date(),\n          uploadOrder: index,\n          isOneOfMultiple: files_list.length != 1\n        });\n        this.uploads_collection.add(file_upload);\n        var checker = new Tabula.ProgressBar({model: file_upload });\n        this.progress_bars.render().$el.find('#progress-bars-container').append(checker.render().el)\n      },this));\n\n      var formdata = new FormData($('form#upload')[0]);\n      $.ajax({\n          url: $('form#upload').attr('action'),\n          type: 'POST',\n          success: _.bind(function (res) {\n              var statuses = JSON.parse(res);\n              _(statuses).each(_.bind(function(status){\n                var file_upload = this.uploads_collection.findWhere({filename: status.filename });\n                if(!file_upload){\n                  console.log(\"couldn't find upload objcect for \" + status.filename );\n                  return\n                }\n                if(status.success){\n                  file_upload.set('file_id', status.file_id);\n                  file_upload.set('id', status.file_id);\n                  file_upload.set('upload_id', status.upload_id);\n                  file_upload.set('error', !status.success);\n                  file_upload.checkStatus(); //\n                }else{\n                  console.log('TODO: failure')\n                  file_upload.set('file_id', status.file_id);\n                  file_upload.set('id', status.file_id);\n                  file_upload.set('upload_id', status.upload_id);\n                  file_upload.set('error', !status.success);\n                }\n              }, this))\n          }, this),\n          error: _.bind(function(a,b,c){\n            $(e.currentTarget).find('button').removeAttr('disabled');\n            this.uploads_collection.each(function(file_upload){\n              file_upload.message = \"Sorry, your file upload could not be processed. (\"+a.statusText+\")\";\n              file_upload.pct_complete = 100;\n              file_upload.error = true;\n            })\n          },this),\n          data: formdata,\n\n          cache: false,\n          contentType: false,\n          processData: false\n      });\n      e.preventDefault();\n      return false; // don't actually submit the form\n    },\n\n    renderFileLibrary: function(added_model){\n      if(this.files_collection.length > 0){\n        $('#library-container').show();\n        ($('#uploaded-files-container').is(':empty') ? this.files_collection.reverse() : this.files_collection).\n        each(_.bind(function(uploaded_file){\n          if(this.$el.find('.file-id-' + uploaded_file.get('id') ).length){\n            return;\n          }\n          var file_element = new Tabula.UploadedFileView({model: uploaded_file}).render().$el;\n          if(added_model && added_model.get('id') == uploaded_file.get('id')){\n            file_element.addClass('flash');\n          }\n          $('#uploaded-files-container').prepend(file_element);\n        }, this));\n\n        //remove anything that was deleted\n        this.$el.find('.uploaded-file').each(_.bind(function(i, el){\n          if(typeof this.files_collection.findWhere({id: $(el).data('id')}) === \"undefined\"){\n            $(el).remove();\n          }\n        }, this));\n\n        $(\"#fileTable\").tablesorter( {\n          headers: { 3: { sorter: \"usLongDate\" },  4: { sorter: false}, 5: {sorter: false} },\n          sortList: [[3,1]]  // initial sort\n          } );\n      }else{\n        $('#library-container').hide();\n        $('#library-container').\n          after(_.template( $('#help-template').html().replace(/nestedscript/g, 'script') )({})).\n          after('<h1>First time using Tabula? Welcome!</h1>');\n        $('.jumbotron.help').css('padding-top', '10px');\n      }\n    },\n\n    render: function(){\n      $('#tabula-app').html( this.template({\n        TABULA_VERSION: Tabula.version,\n        pct_complete: 0,\n        importing: false\n      }) );\n      this.renderFileLibrary();\n      this.renderNotification();\n      this.renderVersion();\n      return this;\n    }\n});\n\nTabula.ProgressBar = Backbone.View.extend({\n    file_id: null,\n    upload_id: null,\n    pct_complete: 0,\n    message: null,\n    tagName: 'div',\n    template: _.template( $('#file-upload-template').html().replace(/nestedscript/g, 'script')),\n    initialize: function(){\n      _.bindAll(this, 'render');\n      this.listenTo(this.model, 'change:pct_complete', this.render);\n    },\n\n    render: function(){\n      if(this.model.get('pct_complete') <= 0){\n        this.$el.find('h4').text(\"Upload Progress\");\n      }else if(this.model.get('pct_complete') >= 100 && !this.model.get('error')){\n        this.$el.find('h4').text(\"Upload Finished.\");\n        this.$el.find('#message').text('');\n        if (!!this.spinobj) {\n            this.spinobj.stop()\n        };\n        if(this.model.get('isOneOfMultiple')){\n          this.remove();\n        }else{\n          window.location = (base_uri || '/') + 'pdf/' + this.model.get('file_id');\n        };\n      }else if(this.model.get('pct_complete') >= 100 && this.model.get('error')){\n        this.$el.find('h4').text(\"Upload Failed.\");\n      }else{\n        this.$el.find('h4').text(\"Importing…\");\n        var spinpots = {\n            lines: 11,\n            length: 5,\n            width: 2,\n            radius: 4,\n            hwaccel: true,\n            top: '0',\n            left: 0\n        };\n        this.spinobj = new Spinner(spinpots).spin(this.$el.find('#spinner')[0]);\n      }\n      this.$el.html(this.template(this.model.attributes));\n      return this;\n    }\n});\n"
  },
  {
    "path": "webapp/static/js/pdf_view.js",
    "content": "Tabula = Tabula || {};\n\nvar clip = null;\nvar base_uri = $('base').attr(\"href\");\n\nPDF_ID = window.location.pathname.replace(base_uri, '').split('/')[1];\nTabula.LazyLoad = 10; // max number of pages around the cursor to show (2x Tabula.LazyLoad pages are shown)\nTabula.HideOnLazyLoad = false; // ideally, set to true, but this requires differently positioned selections, see https://github.com/tabulapdf/tabula/issues/245#issuecomment-75182061\n\nZeroClipboard.config( { swfPath: (base_uri || '/') + \"swf/ZeroClipboard.swf\" } );\n\nTabula.entityMap = {\n  '&': '&amp;',\n  '<': '&lt;',\n  '>': '&gt;',\n  '\"': '&quot;',\n  \"'\": '&#39;',\n  '/': '&#x2F;',\n  '`': '&#x60;',\n  '=': '&#x3D;'\n};\nTabula.escapeHtml = function(string) {\n  return String(string).replace(/[&<>\"'`=\\/]/g, function (s) {\n    return Tabula.entityMap[s];\n  });\n}\n\n\nTabula.Page = Backbone.Model.extend({\n  // number: null, //set on initialize\n  // width: null, //set on initialize\n  // height: null, //set on initialize\n  // rotation: null, //set on initialize\n  initialize: function(){\n    this.set('number_zero_indexed', this.get('number') - 1);\n  },\n  imageUrl: function(){\n    var resolution = Math.max(Tabula.pdf_view.pdf_document.get('thumbnail_sizes')) || 800;\n    this.set('image_url', (base_uri || '/') + 'pdfs/' + PDF_ID + '/document_'+resolution+'_' + this.get('number') + '.png');\n    return this.get('image_url');\n  }\n});\n\nTabula.Pages = Backbone.Collection.extend({\n  model: Tabula.Page,\n  url: null, //set on initialize\n  comparator: 'number',\n  initialize: function(){\n    this.url = (base_uri || '/') + 'pdfs/' + PDF_ID + '/pages.json?_=' + Math.round(+new Date()).toString();\n  }\n});\n\nTabula.Document = Backbone.Model.extend({\n  page_collection: null, //set on initialize\n  selections: null, //set on initialize\n  pdf_id: PDF_ID, //set on initialize\n  url: null, //set on initialize\n\n  initialize: function(options){\n    this.page_collection = new Tabula.Pages([], {pdf_document: this});\n    this.selections = new Tabula.Selections([], {pdf_document: this});\n    this.autodetected_selections = new Tabula.AutodetectedSelections([], {pdf_document: this});\n    this.url = (base_uri || '/') + 'pdf/' + this.pdf_id + '/metadata.json';\n\n    this.set('original_filename', '');\n    this.set('new_filename', false);\n  },\n});\n\nTabula.Selection = Backbone.Model.extend({\n  pdf_id: PDF_ID,\n\n  initialize: function(){\n    _.bindAll(this, 'repeatLassos', 'toCoords');\n  },\n\n  updateCoords: function(){\n    var page = Tabula.pdf_view.pdf_document.page_collection.findWhere({number: this.get('page_number')});\n    var imageWidth = this.get('imageWidth');\n\n    var original_pdf_width = page.get('width');\n    var original_pdf_height = page.get('height');\n    // var pdf_rotation = page.get('rotation');\n\n    var scale = original_pdf_width / imageWidth;\n    var rp = this.attributes.getDims().relativePos;\n    this.set({\n      x1: rp.left * scale,\n      x2: (rp.left + rp.width) * scale,\n      y1: rp.top * scale,\n      y2: (rp.top + rp.height) * scale,\n      width: rp.width * scale, // not used by Tabula right now, but used in the UI elsewhere\n      height: rp.height * scale, // not used by Tabula right now, but used in the UI elsewhere\n    });\n  },\n\n  toCoords: function(){\n    if (this.attributes.getDims){\n      this.updateCoords();\n    }\n    var selection_coords = {\n      page: this.get('page_number'),\n      extraction_method: this.get('extractionMethod') || 'guess',\n      selection_id: this.id,\n      x1:  this.get('x1'),\n      x2: this.get('x2'),\n      y1: this.get('y1'),\n      y2: this.get('y2'),\n      width:  this.get('width'),\n      height:  this.get('height')\n    };\n    return selection_coords;\n  },\n\n  repeatLassos: function() {\n    Tabula.pdf_view.pdf_document.page_collection.each(_.bind(function(page){\n      if(this.get('page_number') < page.get('number')){          // for each page after this one,\n        new_selection = this.clone();                            // and create a new Selection.\n        new_selection.set('page_number', page.get('number'));\n        this.collection.add(Tabula.pdf_view.renderSelection(new_selection.toCoords()));\n        /* which causes thumbnails to be created, Download All button to know about these selections. */\n      }\n    }, this));\n  },\n  repeatLassoOnce: function() {\n    var current_page_number = this.get('page_number');\n    var next_page = Tabula.pdf_view.pdf_document.page_collection.at(Tabula.pdf_view.pdf_document.page_collection.indexOf(Tabula.pdf_view.pdf_document.page_collection.findWhere({number: current_page_number}))+1);\n    new_selection = this.clone();                            // and create a new Selection.\n    new_selection.set('page_number', next_page.get('number'));\n    this.collection.add(Tabula.pdf_view.renderSelection(new_selection.toCoords()));\n  },\n});\n\n// Not currently used at all.\nTabula.Options = Backbone.Model.extend({\n  initialize: function(){\n    _.bindAll(this, 'write');\n    // this.set('multiselect_mode', localStorage.getItem(\"tabula-multiselect-mode\") !== \"false\");\n  },\n  write: function(){\n    // localStorage.setItem(\"tabula-multiselect-mode\", this.get('multiselect_mode'));\n  }\n});\n\n/* What the hell are you doing here, Jeremy?\n  The canonical store of selections now needs to be in Backbone, not in imgareaselect.\n  The UI can listen to the Selections; imgAreaselect creates adds to the collection,\n  causing the thumbnail to be drawn.\n\n  Clearing or repeating is much easier, because we don't have to mess around with the UI.\n  Querying all is likewise easy.\n\n  We could also store extraction option info on the selections, if we want.\n\n  On imgareaselect's _onSelectEnd, add the selection to Selections\n\n  On Selections's remove (or change), find the right imgAreaSelect\n*/\n\nTabula.Selections = Backbone.Collection.extend({\n  // model: Tabula.Selection,\n  comparator: 'page_number',\n  updateOrCreateByVendorSelectorId: function(vendorSelection, pageNumber, imageWidth){\n    var selection = this.get(vendorSelection.id);\n\n    if (selection) { // if it already exists\n      selection.set(_.omit(vendorSelection, 'id'));\n    }\n    else {\n      new_selection_args = _.extend({'page_number': pageNumber,\n                                    'imageWidth': imageWidth,\n                                    'extraction_method': Tabula.pdf_view.options.extraction_method,\n                                    'hidden': false,\n                                    'pdf_document': this.pdf_document},\n                                    vendorSelection);\n      selection = new Tabula.Selection(new_selection_args);\n      this.add(selection);\n    }\n    return selection;\n  },\n  createHiddenSelection: function(sel){\n      new_selection_args = _.extend({'page_number': sel.page,\n                                    'extraction_method': 'spreadsheet',\n                                    'id': Math.random().toString(),\n                                    'hidden': true,\n                                    'pdf_document': this.pdf_document},\n                                    sel);\n      selection = new Tabula.Selection(new_selection_args);\n      this.add(selection);\n      return selection;\n  }\n\n});\n\n\nTabula.AutodetectedSelections = Tabula.Selections.extend({\n  url: null, //set on init\n  initialize: function(){\n    this.url = (base_uri || '/') + 'pdfs/' + PDF_ID + '/tables.json?_=' + Math.round(+new Date()).toString();\n    _.bindAll(this, 'updateOrCreateByVendorSelectorId');\n  },\n\n  parse: function(response){\n    // a JSON list of pages, which are each just a list of coords\n    var tables = [];\n    var selections = _(response).map(_.bind(function(page_tables, listIndex){\n      var pageIndex = listIndex + 1;\n\n      return _(page_tables).map(_.bind(function(tableCoords){\n        if(tableCoords[2] * tableCoords[3] < 400){ //exclude tiny autodetected selections\n          return null;\n        }\n        return {\n          x1: tableCoords[0],\n          y1: tableCoords[1],\n          x2: tableCoords[0] + tableCoords[2],\n          y2: tableCoords[1] + tableCoords[3],\n          width: tableCoords[2],\n          height: tableCoords[3],\n          page: pageIndex,\n          extraction_method: 'spreadsheet',\n          selection_id: null\n        };\n      }, this));\n    }, this));\n    return _.select(_.flatten(selections), function(i){ return i; });\n  }\n\n});\n\nTabula.Query = Backbone.Model.extend({\n  //has selections, data\n  //pertains to DataView\n\n  // on modal exit, destroy this.pdf_view.query\n  // on selection end or download all button, create this.pdf_view.query\n  // in the modal, modify and requery.\n\n  initialize: function(){\n    // should be inited with list_of_coords\n    _.bindAll(this, 'doQuery', 'setExtractionMethod', 'convertTo', 'convertToCSV',\n                    'convertToTabulaExtractorScript', 'convertToBoundingBoxJSON');\n  },\n\n  convertTo: function(format){\n    if(!this.get('data')){\n      throw Error(\"You need to query for data before converting it locally.\");\n    }else{\n      switch(format.toLowerCase()){\n        // case \"XML\":\n        //   return this.convertToXML();\n        // break;\n        case \"bbox\":\n          return this.convertToBoundingBoxJSON();\n        case \"tsv\":\n          return this.convertToCSV(\"\\t\");\n        case \"csv\":\n          return this.convertToCSV();\n        case \"\\uD83D\\uDCA9SV\":\n          return this.convertToCSV(\"\\uD83D\\uDCA9SV\");\n        case \"script\":\n          return this.convertToTabulaExtractorScript();\n        default:\n          throw Error(\"Unknown format: \" + format);\n      }\n    }\n  },\n  convertToCSV: function(delimiter_maybe_undef){\n    var delimiter = typeof delimiter_maybe_undef == \"undefined\" ? ',' : delimiter_maybe_undef\n    var csv = _(this.get('data')).chain().pluck('data').map(function(table){\n      return _(table).chain().map(function(row){\n        return _.map(row, function(cell){ \n          var text = cell.text;\n          text = text.replace(\"\\\"\", \"\\\\\\\"\"); //escape quotes\n          text = text.indexOf(delimiter) > -1 ? \"\\\"\" + text + \"\\\"\" : text; //enquote cells containing the delimiter.\n          return text;\n        }).join(delimiter);\n      }).value();\n    }).flatten(true).value().join(\"\\n\");\n    return csv;\n  },\n  convertToBoundingBoxJSON: function(){\n    return JSON.stringify(this.get('list_of_coords'), null, 4);\n  },\n  convertToTabulaExtractorScript: function(){\n    return _(this.get('list_of_coords')).map(function(c){\n      var extraction_method_switch = \"\";\n      if(c.extraction_method == \"original\"){\n          var extraction_method_switch = \"--no-spreadsheet\";\n      }else if(c.extraction_method == \"spreadsheet\"){\n           var extraction_method_switch = \"--spreadsheet\";\n         }\n      return \"tabula \"+extraction_method_switch+\" -a \"+roundTo(c.y1, 3)+\",\"+roundTo(c.x1, 3)+\",\"+roundTo(c.y2, 3)+\",\"+roundTo(c.x2, 3)+\" -p \"+c.page+\" \\\"$1\\\"\";\n    }).join(\"\\n\");\n  },\n\n  doQuery: function(options) {\n    this.query_data = {\n      'coords': JSON.stringify(this.get('list_of_coords')),\n      'new_filename': null,\n    };\n\n    // print selection coordinates to the console\n    // way easier FOR NOW than downloading the script/JSON\n    console.log(_.map(this.get('list_of_coords'), function(l){ return [l.y1, l.x1, l.y2, l.x2].join(', '); }).join(\"\\n\") );\n\n    // shallow copy the selections collection\n    // so if hte user somehow changes the selections between starting the query and it finishing,\n    // there isn't an error\n    var stashed_selections = new Tabula.Selections(Tabula.pdf_view.pdf_document.selections.models.slice());\n\n    this.trigger(\"tabula:query-start\");\n    window.tabula_router.navigate('pdf/' + PDF_ID + '/extract'); // TODO: this should probably go in a view!! -JBM\n    $.ajax({\n        type: 'POST',\n        url: (base_uri || '/') + 'pdf/' + PDF_ID + '/data',\n        data: this.query_data,\n        success: _.bind(function(resp) {\n          this.set('data', resp);\n\n          // this only needs to happen on the first select, when we don't know what the extraction method is yet\n          // (because it's set by the heuristic on the server-side).\n          // TODO: only execute it when one of the list_of_coords has guess or undefined as its extraction_method\n          _(resp).each(_.bind(function(resp_item, i){\n            var coord_set = this.get('list_of_coords')[resp_item['spec_index']];\n          // _(_.zip(this.get('list_of_coords'), resp)).each(function(stuff, i){\n            // var coord_set = stuff[0];\n            // var resp_item = stuff[1];\n            // if(!coord_set) return; // DIRTY HACK, see https://github.com/tabulapdf/tabula/issues/497\n            //                        // if one set of coords returns 2+ tables, \n            //                        // then this zip won't work.\n            if (stashed_selections.get(coord_set.selection_id)){\n              stashed_selections.get(coord_set.selection_id).\n                set('extraction_method', resp_item[\"extraction_method\"]);\n            }\n            coord_set[\"extraction_method\"] = resp_item[\"extraction_method\"];\n          },this));\n\n          this.trigger(\"tabula:query-success\");\n\n          if (options !== undefined && _.isFunction(options.success)){\n            Tabula.pdf_view.options.success(resp);\n          }\n\n          }, this),\n        error: _.bind(function(xhr, status, error) {\n          console.log(\"error!\", xhr, status);\n          var error_text = xhr.responseText;\n          window.raw_xhr_responseText = xhr.responseText; // for consoles, etc.\n          if(error_text.indexOf(\"DOCTYPE\") != -1){ // we're in Jar/Jetty/whatever land, not rackup land\n            var error_html = $('<div></div>').html( error_text );\n            var summary = error_html.find('#summary').text().trim();\n            var meta = error_html.find('#meta').text().trim();\n            var info = error_html.find('#info').text().trim();\n            error_text = [summary, meta, info].join(\"<br />\");\n          }\n          var debugging_text = \"Tabula API version: \" + Tabula.api_version + \"\\nFilename: \" + Tabula.pdf_view.pdf_document.get('original_filename') + \"\\n\" + error_text\n          this.set('error_message', debugging_text);\n          this.trigger(\"tabula:query-error\");\n          if (options !== undefined && _.isFunction(options.error))\n            options.error(resp);\n        }, this),\n      });\n  },\n  setExtractionMethod: function(extractionMethod){\n    _(this.get('list_of_coords')).each(function(coord_set){ coord_set['extraction_method'] = extractionMethod; });\n  },\n getDataArray: function(){\n    // this.data is a list of responses (because we sent a list of coordinate sets)\n    // $.each( _.pluck(this.model.get('data'), 'data'), function(i, rows) {\n    //   $.each(rows, function(j, row) {\n    //     tableHTML += '<tr><td>' + _.pluck(row, 'text').join('</td><td>') + '</td></tr>';\n    //   });\n    // });\n\n    /* via https://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery\n     * if a PDF contains the string \"<iframe>\" we want to display that, not an actual iframe!\n     */\n\n    if (!this.get('data')){ return []; }\n    var data = _(this.get('data')).chain().pluck('data').map(function(table){\n      return _(table).chain().map(function(row){\n        return (_.pluck(row, 'text')).map(Tabula.escapeHtml);\n      }).value();\n    })/*.flatten(true)*/.value();\n    return data.length == 1 && data[0].length === 0 ? [] : data; // checking whether there's no data, i.e. data == [[]]\n  }\n});\n\nTabula.DataView = Backbone.View.extend({  // one per query object.\n  el: '#tabula-dataview',\n  template: _.template($('#templates #export-page-template').html().replace(/nestedscript/g, 'script')),\n\n  events: {\n    'click .extraction-method-btn:not(.active)': 'queryWithToggledExtractionMethod',\n    'click #download-data': 'setFormAction',\n    'keyup .filename': 'updateFilename',\n    //N.B.: Download button (and format-specific download buttons) are an HTML form, so not handled here.\n    //TODO: handle flash clipboard thingy here.\n    // 'click #copy-csv-to-clipboard':\n    'click #revise-selections': 'closeAndRenderSelectionView'\n  },\n  pdf_view: null, //added on create\n  extractionMethod: \"guess\",\n\n\n\n  initialize: function(stuff){\n    _.bindAll(this, 'render', 'renderFlashClipboardNonsense', 'updateFilename', 'queryWithToggledExtractionMethod', 'closeAndRenderSelectionView', 'setFormAction');\n    this.pdf_view = stuff.pdf_view;\n    this.listenTo(this.model, 'tabula:query-start', this.render);\n    this.listenTo(this.model, 'tabula:query-success', this.render);\n    this.listenTo(this.model, 'tabula:query-error', this.render);\n  },\n  disableDownloadButton: function(){\n    $('#download-data').addClass('download-in-progress');\n    $('#download-data').prop('disabled', 'disabled');\n    window.setTimeout( function(){\n      $('#download-data').removeClass('download-in-progress');\n      $('#download-data').removeProp('disabled');\n    }, 2000);\n  },\n  updateFilename: function(){\n    var new_filename = this.$el.find('#control-panel input.filename').val();\n    if(new_filename.length){\n      this.pdf_view.pdf_document.set('new_filename', new_filename);\n    }\n  },\n  closeAndRenderSelectionView: function(){\n    window.tabula_router.navigate('pdf/' + PDF_ID);\n    this.$el.empty();\n    this.undelegateEvents();\n    this.pdf_view.$el.show();\n    this.pdf_view.render();\n\n    $('body').removeClass('page-export');\n    $('body').addClass('page-selections');\n\n    var oldSelections = this.pdf_view.pdf_document.selections.models.map(function(sel){\n      var selection = Tabula.pdf_view.renderSelection(sel.toCoords());\n      // selection.attributes.rebind(); // o. m. g.\n      return selection;\n    });\n    this.pdf_view.pdf_document.selections.reset(oldSelections);\n    _(this.pdf_view.components[\"sidebar_view\"].thumbnail_list_view.thumbnail_views).each(function(v){ v.delegateEvents() });\n  },\n\n  setFormAction: function(e){\n    var formActionUrl = $(e.currentTarget).data('action');\n    this.$el.find('#download-form').attr('action', formActionUrl);\n    this.$el.find('#download-form').submit();\n    this.disableDownloadButton();\n  },\n\n  render: function(e){\n    document.title=\"Export Data | Tabula\";\n    var uniq_extraction_methods = _.uniq(_(this.model.get('list_of_coords')).pluck('extraction_method'));\n\n    // save the current scroll position (if unset), then scroll to the top\n    if(!Tabula.pdf_view.selectionScrollTop){\n      Tabula.pdf_view.selectionScrollTop = $(document).scrollTop();\n    }\n    $(document).scrollTop(0);\n\n    //TODO: move flash_borked to this object (dataview) away from pdf_view\n    $('body').removeClass('page-selections');\n    $('body').addClass('page-export');\n    this.delegateEvents();\n\n    this.pdf_view.$el.hide();\n    $('.selection-box').css('visibility', 'hidden');\n    $('.table-region').remove();\n    $('.selection-show').remove(); // nuke thumbs, we'll put 'em back in a second\n\n    this.$el.html(this.template({\n      pdf_id: PDF_ID,\n      data: this.model.getDataArray(),\n      loading: !(this.model.get('data') || this.model.get('error_message')),\n      error_message: this.model.get('error_message')\n    }));\n    this.$el.find('#control-panel').html(\n      _.template($('#templates #export-control-panel-template').html().replace(/nestedscript/g, 'script'))(\n        _(this.pdf_view.pdf_document.attributes).extend({\n          pdf_id: PDF_ID,\n          list_of_coords: JSON.stringify(this.model.get('list_of_coords')),\n          copyDisabled: Tabula.pdf_view.flash_borked ? 'disabled=\"disabled\" data-toggle=\"tooltip\" title=\"'+Tabula.pdf_view.flash_borken_message+'\"' : '',\n          disableIfNoData: (_.isNull(this.model.get('data')) || typeof(this.model.get('data')) === \"undefined\") ? 'disabled=\"disabled\"' : ''\n        })\n    ));\n    this.$el.find('#sidebar').html(\n      _.template($('#templates #export-page-sidebar-template').html().replace(/nestedscript/g, 'script')) (\n        {\n          pdf_id: PDF_ID,\n          disableExtractionMethodButtons: _.isNull(this.model.data) || uniq_extraction_methods.length > 1 ? 'disabled=\"disabled\"' : '',\n        }\n    ));\n    this.renderFlashClipboardNonsense();\n    if(!this.model.get('data')) this.startSpinner();\n\n    if (uniq_extraction_methods.length == 1){\n      // prospectively support renaming the methods in tabula-extractor to \"lattice\"/\"stream\"\n      // and cope with \"basic\" extraction algorithm ID in tabula-java\n      // https://github.com/tabulapdf/tabula-extractor/issues/96\n      if ([\"basic\", \"original\", \"stream\"].indexOf(uniq_extraction_methods[0]) > -1){\n        uniq_extraction_methods[0] = \"original\";\n      }else if([\"spreadsheet\", \"lattice\"].indexOf(uniq_extraction_methods[0]) > -1){\n        uniq_extraction_methods[0] = \"spreadsheet\";\n      }\n      this.$el.find('#' + uniq_extraction_methods[0] + '-method-btn').button('toggle');\n    }else{\n      console.log(\"A mix of unique extraction methods found, not selecting either extraction method radio button: \" + uniq_extraction_methods.join(\", \"))\n    }\n\n    this.$el.find('.has-tooltip').tooltip();\n\n    return this;\n  },\n\n  startSpinner: function(){\n    var SPINNER_OPTS = {\n      lines: 10, // The number of lines to draw\n      length: 5, // The length of each line\n      width: 2, // The line thickness\n      radius: 5, // The radius of the inner circle\n      corners: 1, // Corner roundness (0..1)\n      rotate: 0, // The rotation offset\n      direction: 1, // 1: clockwise, -1: counterclockwise\n      color: '#000', // #rgb or #rrggbb\n      speed: 1.1, // Rounds per second\n      trail: 60, // Afterglow percentage\n      shadow: false, // Whether to render a shadow\n      hwaccel: true, // Whether to use hardware acceleration\n      className: 'spinner', // The CSS class to assign to the spinner\n      zIndex: 2e9, // The z-index (defaults to 2000000000)\n      top: 'auto', // Top position relative to parent in px\n      left: 'auto' // Left position relative to parent in px\n    };\n    new Spinner(SPINNER_OPTS).spin($('#spinner').get(0));\n  },\n\n  renderFlashClipboardNonsense: function(){\n    if(!Tabula.pdf_view.client){\n      try{\n        Tabula.pdf_view.client = new ZeroClipboard();\n      }catch(e){\n        this.$el.find('#copy-csv-to-clipboard').hide();\n      }\n    }\n    if( !Tabula.pdf_view.flash_borked ){\n        Tabula.pdf_view.client.on( 'ready', _.bind(function(event) {\n          Tabula.pdf_view.client.clip( this.$el.find(\"#copy-csv-to-clipboard\") );\n          Tabula.pdf_view.client.on( 'copy', _.bind(function(event) {\n            var clipboard = event.clipboardData;\n            console.log('clippy thingy clicked', $('#download-form select').val());\n\n            var button_text = this.$el.find(\"#copy-csv-to-clipboard .clipboard-text\");\n            button_text.text(\"Copied!\");\n            window.setTimeout(_.bind(function(){\n              button_text.text(\"Copy to Clipboard\");\n            },this), 2000);\n\n            var tableData = Tabula.pdf_view.query.convertTo($('#download-form select').val());\n            clipboard.setData( 'text/plain', tableData );\n          }, this) );\n\n          this.$el.find('.modal-footer button').prop('disabled', '');\n\n        }, this) );\n\n        Tabula.pdf_view.client.on( 'error', _.bind(function(event) {\n          //disable all clipboard buttons, add tooltip, event.message\n          Tabula.pdf_view.flash_borked = true;\n          Tabula.pdf_view.flash_borken_message = event.message;\n          this.$el.find('#copy-csv-to-clipboard').addClass('has-tooltip').tooltip();\n          console.log( 'ZeroClipboard error of type \"' + event.name + '\": ' + event.message );\n          ZeroClipboard.destroy();\n          this.$el.find('.modal-footer button').prop('disabled', '');\n        },this) );\n    }\n\n    return this;\n  },\n\n  queryWithToggledExtractionMethod: function(e){\n    this.model.set('data', null);\n    var extractionMethod = $(e.currentTarget).data('method');\n    this.pdf_view.options.set('extraction_method', extractionMethod);\n    Tabula.pdf_view.query.setExtractionMethod(extractionMethod);\n    Tabula.pdf_view.query.doQuery();\n  },\n});\n\nTabula.DocumentView = Backbone.View.extend({ // Singleton\n  events: {\n  },\n  pdf_view: null, //added on create\n  page_views: {},\n  rectangular_selector: null,\n\n  _selectionsGetter: function(target) {\n    return _(Tabula.pdf_view.pdf_document.selections.where({page_number: $(target).data('page')})).map(function(i){ return i.attributes; });\n  },\n\n  initialize: function(stuff){\n    _.bindAll(this, 'render', 'removePage', 'addSelection', '_onRectangularSelectorEnd', '_selectionsGetter');\n    this.pdf_view = stuff.pdf_view;\n    this.listenTo(this.collection, 'remove', this.removePage);\n\n    // attach rectangularSelector to main page container\n    this.rectangular_selector = new RectangularSelector(\n      this.$el,\n      {\n        selector: '#pages-container .pdf-page img',\n        end: this._onRectangularSelectorEnd,\n        areas: this._selectionsGetter,\n        validSelection: function(selection) {\n            return (selection.absolutePos.width > $(selection.pageView).width() * 0.01) &&\n                (selection.absolutePos.height > $(selection.pageView).height() * 0.01);\n        }\n      }\n    );\n  },\n\n  addSelection: function (d) {\n    var page_number = $(d.pageView).data('page') || d.pageNumber;\n    var pv = this.page_views[page_number];\n    var rs = new ResizableSelection({\n      position: d.absolutePos,\n      target: pv.$el.find('img'),\n      areas: this._selectionsGetter\n    });\n    rs.on({\n      resize: _.debounce(pv._onSelectChange, 100),\n      remove: pv._onSelectCancel\n    });\n    pv._onSelectEnd(rs);\n    this.$el.append(rs.el);\n    rs.$el.css('z-index', 100 - this._selectionsGetter($(d.pageView)).length);\n  },\n\n  // listens to mouseup of RectangularSelector\n  _onRectangularSelectorEnd: function(d) {\n    this.addSelection(d);\n  },\n\n  removePage: function(pageModel){\n    var page_view = this.page_views[pageModel.get('number')];\n\n    page_view.$el.fadeOut(200, function(){\n      deleted_page_height = page_view.$el.height();\n      deleted_page_top = page_view.$el.offset()[\"top\"];\n      page_view.remove();\n    });\n  },\n\n  render: function(){\n    if(!Tabula.LazyLoad){ // old-style, non-lazyload behavior\n      _(this.page_views).each(_.bind(function(page_view, index){\n        var already_on_page = $('#page-' + parseInt(index)+1).length;\n        if(!already_on_page) this.$el.append(page_view.render().el);\n      }, this));\n    }else{\n      //useful in the console for debugging: \n      // $('.pdf-page:visible').map(function(i, el){ return $(el).find('img').data('page') }).get();\n\n\n      // just so pages end up in the right order, we have to loop AWAY FROM the cursor in both directions\n      // so if the cursor is at 1.\n      for (var number=Tabula.pdf_view.lazyLoadCursor;number>0;number--){\n        var page_view = this.page_views[number];\n        if(!page_view) continue; // this is the first render, and there are no pages (probably!)\n        var page_el = $('#page-' + number);\n        var visible_on_page = page_el.filter(':visible').length;\n        if(visible_on_page && Tabula.HideOnLazyLoad){\n          if(Math.abs(Tabula.pdf_view.lazyLoadCursor - number) >= Tabula.LazyLoad ) {\n            $('#page-' + number).hide();\n            // console.log('hide', number)\n          }\n        }else{\n          if(Math.abs(Tabula.pdf_view.lazyLoadCursor - number) < Tabula.LazyLoad ) {\n            if(page_el.length){\n              page_view.$el.show();\n              // console.log('show ' + number);\n            }else{\n              this.$el.prepend(page_view.render().el);\n            }\n          }\n        }\n      }\n      for (var number=Tabula.pdf_view.lazyLoadCursor+1;number<=_(this.page_views).keys().length;number++){\n        var page_view = this.page_views[number];\n        if(!page_view) continue; // this is the first render, and there are no pages (probably!)\n        var page_el = $('#page-' + number);\n        var visible_on_page = page_el.filter(':visible').length;\n        if(visible_on_page && Tabula.HideOnLazyLoad){\n          if(Math.abs(Tabula.pdf_view.lazyLoadCursor - number) >= Tabula.LazyLoad ) {\n            $('#page-' + number).hide();\n          }\n        }else{\n          if(Math.abs(Tabula.pdf_view.lazyLoadCursor - number) < Tabula.LazyLoad ) {\n            if(page_el.length){\n              page_view.$el.show();\n              // console.log('show ' + number);\n            }else{\n              this.$el.append(page_view.render().el);\n\n            }\n          }\n        }\n      }\n    }\n              // should remove the \"hidden\" selections\n              // then should render the selections for this page from autodetectedSelections the \"normal\" way.\n              Tabula.pdf_view.pdf_document.selections.filter(function(sel){ return sel.get('hidden') && sel.get('page') <= number}).map(function(hidden_selection){\n                Tabula.pdf_view.pdf_document.selections.remove(hidden_selection);\n                var new_selection = Tabula.pdf_view.renderSelection(hidden_selection.attributes); // adds it to Tabula.pdf_view.pdf_document.selections\n                return new_selection;\n              });\n    return this;\n  }\n});\n\nTabula.PageView = Backbone.View.extend({ // one per page of the PDF\n  document_view: null, //added on create\n  className: 'pdf-page',\n  iasAlreadyInited: false,\n  selections: null,\n\n  id: function(){\n    return 'page-' + this.model.get('number');\n  },\n\n  template: _.template($('#templates #page-template').html().replace(/nestedscript/g, 'script')) ,\n\n  'events': {\n   // 'click i.rotate-left i.rotate-right': 'rotate_page',\n  },\n\n  initialize: function(stuff){\n    this.pdf_view = stuff.pdf_view;\n    _.bindAll(this, 'rotate_page', 'createTables',\n      '_onSelectStart', '_onSelectChange', '_onSelectEnd', '_onSelectCancel', 'render');\n    this.listenTo(Tabula.pdf_view.pdf_document, 'change', function(){ this.render(); });\n    this.listenTo(Tabula.pdf_view.pdf_document, 'change', function(){ this.render(); });\n  },\n\n  render: function(){\n    this.$el.html(this.template({\n                    'number': this.model.get('number'),\n                    'image_url': this.model.imageUrl()\n                  }));\n    this.$el.find('img').attr('data-page', this.model.get('number'))\n                        .attr('data-original-width', this.model.get('width'))\n                        .attr('data-original-height', this.model.get('height'));\n                        // .attr('data-rotation', this.model.get('rotation'));\n    this.$image = this.$el.find('img');\n    return this;\n  },\n\n  createTables: function(asfd){\n    this.iasAlreadyInited = true;\n  },\n\n  _onSelectStart: function(selection) {\n    Tabula.pdf_view.pdf_document.selections.updateOrCreateByVendorSelectorId(selection,\n                                                                  this.model.get('number'),\n                                                                  this.$image.width());\n  },\n\n  _onSelectChange: function(selection) {\n    Tabula.pdf_view.pdf_document.selections.updateOrCreateByVendorSelectorId(selection,\n                                                                  this.model.get('number'),\n                                                                  this.$image.width());\n  },\n\n  _onSelectEnd: function(selection) {\n    var sel = Tabula.pdf_view.pdf_document.selections.updateOrCreateByVendorSelectorId(selection,\n                                                                            this.model.get('number'),\n                                                                            this.$image.width());\n\n    // deal with invalid/too-small selections somehow (including thumbnails)\n    if (selection.width === 0 && selection.height === 0) {\n      $('#thumb-' + this.$image.attr('id') + ' #vendorSelection-show-' + selection.id).css('display', 'none');\n      selection.remove();\n    }\n\n    // if this is not the last pager\n    if(this.model != this.model.collection.last()) {\n      var but_id = this.model.get('number') + '-' + selection.id;  //create a \"Repeat this Selection\" button\n      var button = $('<div class=\"btn-group repeat-lassos-group\" id=\"'+but_id+'\"> \\\n      <button type=\"button\" class=\"btn btn-default repeat-lassos\">Repeat this Selection</button>\\\n      <button type=\"button\" class=\"btn btn-default dropdown-toggle dropdown-toggle-split\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">\\\n        <span class=\"caret\"></span>\\\n        <span class=\"sr-only\">Toggle Dropdown</span>\\\n      </button>\\\n      <ul class=\"dropdown-menu\">\\\n        <li><a class=\"dropdown-item repeat-lassos\" href=\"#\">Repeat to All Pages</a></li>\\\n        <li><a class=\"dropdown-item repeat-lasso-once\" href=\"#\">Repeat to Next Page</a></li>\\\n      </ul>\\\n    </div>');\n      button.find(\"button\").data(\"selectionId\", selection.id);\n      button.find(\"a\").data(\"selectionId\", selection.id);\n      selection.$el.append(button);\n    }\n\n    Tabula.pdf_view.components['control_panel'].render(); // deals with buttons that need blurred out if there's zero selections, etc.\n  },\n\n  // vendorSelection\n  _onSelectCancel: function(selection) {\n    // remove repeat lassos button\n    var but_id = this.$image.attr('id') + '-' + selection.id;\n    $('button#' + but_id).remove();\n\n    // find and remove the canceled selection from the collection of selections. (triggering remove events).\n    var sel = Tabula.pdf_view.pdf_document.selections.get(selection.id);\n    removed_selection = Tabula.pdf_view.pdf_document.selections.remove(sel);\n\n    Tabula.pdf_view.components['control_panel'].render(); // deal with buttons that need blurred out if there's zero selections, etc.\n  },\n\n  rotate_page: function(t) {\n      alert('not implemented');\n  }\n});\n\nTabula.ControlPanelView = Backbone.View.extend({ // only one\n  events: {\n    'click #clear-all-selections': 'clearAllSelections',\n    'click #restore-detected-tables': 'restoreDetectedTables',\n    'click #all-data': 'queryAllData',\n    'click #repeat-lassos': 'repeatLassos',\n    'click #save-template': 'saveTemplate',\n  },\n\n  template: _.template($('#templates #select-control-panel-template').html().replace(/nestedscript/g, 'script')),\n  initialize: function(stuff){\n    this.pdf_view = stuff.pdf_view;\n    this.saved_template_collection = stuff.saved_template_collection;\n    _.bindAll(this, 'queryAllData', 'render', 'saveTemplate');\n    this.listenTo(this.pdf_view.pdf_document, 'sync', this.render );\n    this.saved_template_library_view = new Tabula.SavedTemplateLibraryView({collection: this.saved_template_collection})\n  },\n\n  /* in case there's a PDF with a complex format that's repeated on multiple pages */\n  repeatFirstPageLassos: function(){\n    alert('not yet implemented');\n    return;\n    /* TODO: write this */\n  },\n\n  clearAllSelections: function(){\n    _(Tabula.pdf_view.pdf_document.selections.models.slice()).each(function(i){ if(typeof i.attributes.remove !== \"undefined\") i.attributes.remove(); }); // call remove() on the vendorSelection of each seleciton; except for \"hidden\" selections that don't have one.\n    Tabula.pdf_view.pdf_document.selections.reset([]);\n    Tabula.pdf_view.components['control_panel'].render(); // deal with buttons that need blurred out if there's zero selections, etc.\n    // reset doesn't trigger the right events because we have to remove from the collection and from the page (with selection.remove())\n    // we can't use _.each because we're mutating the collection that we're iterating over\n    // ugh\n  },\n\n  saveTemplate: function(e){\n    $btn = $(e.currentTarget);\n    $btnText = $btn.find(\".button-text\");\n    var oldButtonText = $btnText.text();\n    $btn.attr(\"disabled\", \"disabled\");\n    $btnText.text(\"Saving...\");\n    this.pdf_view.saveTemplate(function(){ \n      $btnText.text(\"Saved!\");\n      window.setTimeout( function(){\n        $btn.removeAttr(\"disabled\");\n        $btn.removeProp(\"disabled\");\n        $btnText.text(oldButtonText);\n      }, 2000);\n    });\n  },\n\n  restoreDetectedTables: function(){\n    var autodetected_selections = this.pdf_view.pdf_document.autodetected_selections.models.map(function(sel){\n      return Tabula.pdf_view.renderSelection(sel.attributes);\n    });\n    this.pdf_view.pdf_document.selections.reset(autodetected_selections);\n  },\n\n  queryAllData : function(){\n    var list_of_all_coords = Tabula.pdf_view.pdf_document.selections.invoke(\"toCoords\");\n\n    //TODO: figure out how to handle extraction methods when there are multiple selections\n    // should it be set globally, or per selection?\n    // actually, how to handle extraction method is a bit of an open question.\n    // should we support in the UI extraction methods per selection?\n    // if so, what does the modal show if its showing results from more than one selection?\n    // maybe it only shows them if they match?\n    // or not at all ever?\n    // but then we need to make it clearer in the UI that you are \"editing\" a selection.\n    // which will require different reactions with multiselect mode:\n    // when you finish a query, then still pop up its data.\n    // when you click or move an already-selected query, then you're \"editing\" it?\n    // hmm.\n    Tabula.pdf_view.query = new Tabula.Query({list_of_coords: list_of_all_coords, extraction_method: 'guess'});\n    Tabula.pdf_view.createDataView();\n    Tabula.pdf_view.query.doQuery();\n  },\n\n  render: function(){\n    var numOfSelectionsOnPage = this.pdf_view.totalSelections();\n    this.$el.html(this.template(\n              _(this.pdf_view.pdf_document.attributes).extend({\n                  'disable_clear_all_selections': numOfSelectionsOnPage <= 0 ? 'disabled=\"disabled\"' : '' ,\n                  'disable_download_all': numOfSelectionsOnPage <= 0 ? 'disabled=\"disabled\"' : '',\n\n                  // three states: autodetection still incomplete, autodetection done but no tables found, autodetection done and tables found\n                  'restore_detected_tables': this.pdf_view.hasAutodetectedTables ? \"autodetect-finished\" : \"autodetect-in-progress\",\n                  'disabled_if_there_are_selections': numOfSelectionsOnPage > 0 || this.pdf_view.pdf_document.autodetected_selections.size() === 0 ? 'disabled=\"disabled\"' : '',\n\n                  'disable_save_template':numOfSelectionsOnPage == 0 ? 'disabled=\"disabled\"' : '',\n                  'disable_load_template': numOfSelectionsOnPage > 0 ? 'disabled=\"disabled\"' : ''\n\n                  })));\n    \n    this.$el.find(\"#template-dropdown-templates-list-container\").html(this.saved_template_library_view.render().el);\n\n    return this;\n  },\n});\n\nTabula.SidebarView = Backbone.View.extend({\n  className: 'sidebar-view',\n  thumbnail_list_view: null, // defined on initialize\n  pdf_view: null,            // defined on initialize\n  template: _.template($('#templates #select-sidebar-template').html().replace(/nestedscript/g, 'script')),\n  initialize: function(stuff){\n    _.bindAll(this, 'render')\n    this.pdf_view = stuff.pdf_view;\n    this.thumbnail_list_view = new Tabula.ThumbnailListView(stuff);\n  },\n  render: function(){\n    this.$el.html(this.template({\n                    'original_filename': this.pdf_view.pdf_document.get('original_filename')\n                  }));\n    this.thumbnail_list_view.$el = this.$el.find(\"#thumbnail-list\");\n    this.thumbnail_list_view.render();\n    return this;\n  }\n}),\n\nTabula.ThumbnailListView = Backbone.View.extend({ // only one\n  tagName: 'ul',\n  className: 'thumbnail-list',\n  thumbnail_views: {},\n  pdf_view: null, // defined on initialize\n  initialize: function(stuff){\n    this.pdf_view = stuff.pdf_view;\n    _.bindAll(this, 'addSelectionThumbnail', 'removeSelectionThumbnail', 'changeSelectionThumbnail',\n                    'removeThumbnail', 'render');\n\n    this.listenTo(this.collection, 'remove', this.removeThumbnail);\n\n    this.listenTo(this.pdf_view.pdf_document.selections, 'sync', this.render);\n    this.listenTo(this.pdf_view.pdf_document.selections, 'add', this.addSelectionThumbnail); // render a thumbnail selection\n    this.listenTo(this.pdf_view.pdf_document.selections, 'change', this.changeSelectionThumbnail); // render a thumbnail selection\n    this.listenTo(this.pdf_view.pdf_document.selections, 'remove', this.removeSelectionThumbnail); // remove a thumbnail selection\n  },\n  addSelectionThumbnail: function (new_selection){\n    if(this.thumbnail_views[new_selection.get('page_number')].$el.find('img').length){\n      this.thumbnail_views[new_selection.get('page_number')].createSelectionThumbnail(new_selection);\n    }\n  },\n  changeSelectionThumbnail: function (selection){\n    this.thumbnail_views[selection.get('page_number')].changeSelectionThumbnail(selection);\n  },\n  removeSelectionThumbnail: function (selection){\n    this.thumbnail_views[selection.get('page_number')].removeSelectionThumbnail(selection);\n  },\n\n  removeThumbnail: function(pageModel){\n    var thumbnail_view = this.thumbnail_views[pageModel.get('number')];\n    thumbnail_view.$el.fadeOut(200, function(){ thumbnail_view.remove(); });\n  },\n\n  render: function(){\n    if(!Tabula.LazyLoad){ // old-style, un-lazyload behavior where all pages are shown at once.\n      _(this.thumbnail_views).each(_.bind(function(thumbnail_view, index){\n        var already_on_page = $('#page-' + parseInt(index)+1).length;\n        if(!already_on_page) this.$el.append(thumbnail_view.render().el);\n      }, this));\n    }else{\n\n      for (var number=Tabula.pdf_view.lazyLoadCursor;number>0;number--){\n        var thumbnail_view = this.thumbnail_views[number];\n        if(!thumbnail_view) continue; // this is the first render, and there are no pages (or there's a problem!)\n        var thumb_el = $('#thumb-page-' + number);\n        var visible_on_page = thumb_el.filter(':visible').length;\n        if(visible_on_page && Tabula.HideOnLazyLoad){\n          if(Math.abs(Tabula.pdf_view.lazyLoadCursor - number) >= Tabula.LazyLoad ) {\n            $('#thumb-page-' + number).hide();\n            // console.log('hide', number)\n          }\n        }else{\n          if(Math.abs(Tabula.pdf_view.lazyLoadCursor - number) < Tabula.LazyLoad ) {\n            if(thumb_el.length){\n              thumbnail_view.$el.show();\n              // console.log('show ' + number);\n            }else{\n              this.$el.prepend(thumbnail_view.render().el);\n              // console.log('append ' + number);\n            }\n          }\n        }\n      }\n      for (var number=Tabula.pdf_view.lazyLoadCursor+1;number<=_(this.thumbnail_views).keys().length;number++){\n        var thumbnail_view = this.thumbnail_views[number];\n        if(!thumbnail_view) continue; // this is the first render, and there are no pages (probably!)\n        var thumb_el = $('#thumb-page-' + number);\n        var visible_on_page = thumb_el.filter(':visible').length;\n        if(visible_on_page && Tabula.HideOnLazyLoad){\n          if(! (Math.abs(Tabula.pdf_view.lazyLoadCursor - number) < Tabula.LazyLoad )) {\n            $('#thumb-page-' + number).hide();\n            // console.log('hide', number)\n          }\n        }else{\n          if(Math.abs(Tabula.pdf_view.lazyLoadCursor - number) < Tabula.LazyLoad ) {\n            if(thumb_el.length){\n              thumbnail_view.$el.show();\n              // console.log('show ' + number);\n            }else{\n              this.$el.append(thumbnail_view.render().el);\n              // console.log('append ' + number);\n            }\n          }\n        }\n      }\n\n    }\n\n    return this;\n  }\n});\n\nTabula.ThumbnailView = Backbone.View.extend({ // one per page\n  'events': {\n    // on load, create an empty div with class 'selection-show' to be the selection thumbnail.\n    'load .thumbnail-list li img': function() { $(this).after($('<div />', { class: 'selection-show'})); },\n    'click .delete-page': 'deletePage',\n    'click a': 'scrollToPage'\n  },\n  tagName: 'li',\n  className: \"page-thumbnail page\",\n  id: function(){\n    return 'thumb-page-' + this.model.get('number');\n  },\n\n  // initialize: function(){\n  // },\n  template: _.template($('#templates #thumbnail-template').html().replace(/nestedscript/g, 'script')),\n\n  initialize: function(){\n    _.bindAll(this, 'render', 'createSelectionThumbnail', 'changeSelectionThumbnail', 'removeSelectionThumbnail');\n    this.listenTo(Tabula.pdf_view.pdf_document, 'change', function(){ this.render(); });\n    this.listenTo(Tabula.pdf_view.pdf_document, 'change', function(){ this.render(); });\n  },\n\n  // why do we have this?\n  // due to #586 / https://github.com/tabulapdf/tabula/commit/d3bdb4957ebc84ef2c2b0ceebb6f2ea5cca0faed,\n  // Tabula now works under a relative path, using the <base> tag.\n  // however, the base tag breaks anchor links, since <base> applies to them too.\n  // so we have to replicate the \"normal\" anchor-link click behavior here.\n  scrollToPage: function(e){\n    console.log(\"scrollToPage\");\n    var hashToGoTo = $(e.currentTarget).attr('href').replace(\"#\", \"\")\n    document.location.hash=hashToGoTo;\n    e.preventDefault();\n  },\n\n  deletePage: function(){\n    if (!confirm('Delete page ' + this.model.get('number') + '?')) return;\n    Tabula.pdf_view.pdf_document.page_collection.remove( this.model );\n  },\n\n  render: function(){\n    this.$el.html(this.template({\n                    'number': this.model.get('number'),\n                    'image_url': this.model.imageUrl()\n                  }));\n\n    // stash some selectors (which don't exist at init)\n    this.$img = this.$el.find('img');\n    this.img = this.$img[0];\n    this.$img.attr('data-page', this.model.get('number'));\n\n    return this;\n  },\n\n  createSelectionThumbnail: function(selection) {\n    var $sshow = $('<div class=\"selection-show\" id=\"selection-show-' + selection.cid + '\" />').css('display', 'block');\n    this.$el.append( $sshow );\n    this.changeSelectionThumbnail(selection);\n  },\n\n  changeSelectionThumbnail: function(selection){\n    var $sshow = this.$el.find('#selection-show-' + selection.cid);\n\n    // don't break everything if the sidebar happens to be broken.\n    var thumbScale = this.$img ? this.$img.width() / selection.get('imageWidth') : 0;\n    var left = parseFloat(this.$el.css('padding-left'));\n    var top = parseFloat(this.$el.css('padding-top'));\n\n    // if data has gotten messed up somewhere\n    if(!selection.attributes) return;\n\n    // if thumbnail doesn't exist (probably because this selection is hidden in an unshown page)\n    if(!selection.attributes.getDims) return;\n\n    var s = selection.attributes.getDims().relativePos;\n\n    $sshow.css('top', (top + (s.top * thumbScale)) + 'px')\n      .css('left', (left + (s.left * thumbScale)) + 'px')\n      .css('width', (s.width * thumbScale) + 'px')\n      .css('height', (s.height * thumbScale) + 'px');\n  },\n\n  removeSelectionThumbnail: function(selection){\n    var $sshow = this.$el.find('#selection-show-' + selection.cid);\n    $sshow.remove();\n  }\n});\n\nTabula.PDFView = Backbone.View.extend(\n  _.extend({\n    el : '#tabula-app',\n\n    events : {\n    },\n    lastQuery: [{}],\n    pageCount: undefined,\n    lazyLoadCursor:  parseInt(window.location.hash.replace(\"#page-\", '')) || 1, // 0 is invalid, because pages are one-indexed\n    components: {},\n\n    hasAutodetectedTables: false,\n    global_options: null,\n\n    initialize: function(){\n      _.bindAll(this, 'render', 'addOne', 'addAll', 'totalSelections', 'renderSelection',\n        'createDataView', 'checkForAutodetectedTables', 'getData', 'handleScroll',\n        'loadSavedTemplate', 'saveTemplate', 'saveTemplateAs');\n\n      this.pdf_document = new Tabula.Document({\n        pdf_id: PDF_ID,\n      });\n\n      this.pdf_document.fetch({\n        success: function(m){ }, \n        error: function(m, r, o){ console.log(\"error\", m, r, o) }\n      });\n\n      this.options = new Tabula.Options();\n      this.listenTo(this.options, 'change', this.options.write);\n\n      // we'll never be ~adding~ individual pages, I don't think (hence no 'add' event)\n      this.listenTo(this.pdf_document.page_collection, 'sync', this.addAll);\n      this.listenTo(this.pdf_document.page_collection, 'reset', this.addAll);\n      this.listenTo(this.pdf_document.page_collection, 'remove', this.removePage);\n      // this caused page ordering issues. Makes me wonder if pdf_view rendering is not idempotent.\n      // anyways, I don't remember why I had this. probably you shouldn't reenable it.\n      // this.listenTo(this.pdf_document.page_collection, 'all', _.bind(function(){ console.log('pdfview render page all'); this.render()}, this));\n      this.saved_template_collection = new Tabula.TemplatesCollection(); // this is mandatorily ordered above `new Tabula.ControlPanelView`\n      this.saved_template_collection.fetch();\n\n      this.components['document_view'] = new Tabula.DocumentView({el: '#pages-container' , pdf_view: this, collection: this.pdf_document.page_collection}); //creates page_views\n      this.components['control_panel'] = new Tabula.ControlPanelView({pdf_view: this, saved_template_collection: this.saved_template_collection});\n      this.components['sidebar_view'] = new Tabula.SidebarView({pdf_view: this, collection: this.pdf_document.page_collection});\n\n      $(document).on('scroll', _.throttle(this.handleScroll, 100, {leading: false}));\n      $('#sidebar').on('scroll', _.throttle(this.handleScroll, 100, {leading: false}));\n\n\n      $('body').\n        on(\"click\", \".repeat-lassos\", function(e){\n          var selectionId = $(e.currentTarget).data('selectionId');\n          var selection = Tabula.pdf_view.pdf_document.selections.get(selectionId);\n          selection.repeatLassos();\n          e.preventDefault();\n        });\n      $('body').\n        on(\"click\", \".repeat-lasso-once\", function(e){\n          var selectionId = $(e.currentTarget).data('selectionId');\n          var selection = Tabula.pdf_view.pdf_document.selections.get(selectionId);\n          selection.repeatLassoOnce();\n          e.preventDefault();\n        });\n\n\n      window.tabula_router.route(\"pdf/:file_id/extract\", function(){\n        Tabula.pdf_view.createDataView();\n        Tabula.pdf_view.query.doQuery();\n      } );\n\n      _(['', '/', '/select']).each(function(path_suffix){\n        window.tabula_router.route(\"pdf/:file_id\" + path_suffix, function(){\n          Tabula.pdf_view.components['data_view'].closeAndRenderSelectionView();\n        });\n      });\n    },\n\n    handleScroll: function(e){\n      // check which page_view is \"active\" (i.e. topmost that's partially in the window)\n      var pdf_pages = $('.pdf-page');\n      var new_cursor = 0;\n      for (i=0; i<pdf_pages.length; i++){\n        var el = pdf_pages[i];\n        if(isElementPartiallyInContainer(el, this.components['document_view'].el)){\n          $('.page-thumbnail.active').removeClass('active');\n          this.components['sidebar_view'].thumbnail_list_view.thumbnail_views[i+1].$el.addClass('active');\n          new_cursor = Math.max(new_cursor, parseInt($(el).find('img').data('page')));\n          break;\n        }\n      }\n      var thumbs = $('.page-thumbnail');\n      for (i=0; i<thumbs.length; i++){\n        var el = thumbs[i];\n        if(isElementPartiallyInContainer(el, this.components['sidebar_view'].el)){\n          new_cursor = Math.max(new_cursor, parseInt($(el).find('img').data('page')));\n          break;\n        }\n      }\n      Tabula.pdf_view.lazyLoadCursor = new_cursor;\n\n      this.components['document_view'].render(); \n      this.components['sidebar_view'].thumbnail_list_view.render();\n      // console.log(\"cursor\", Tabula.pdf_view.lazyLoadCursor)\n    },\n\n    getData: function(){\n      this.pdf_document.page_collection.fetch({\n        success: _.bind(function(){\n          this.checkForAutodetectedTables();\n        }, this),\n        error: _.bind(function(){\n          console.log('404'); //TODO: make this a real 404, with the right error code, etc.\n          $('#tabula').html(\"<h1>Error: We couldn't find your document.</h1><h2>Double-check the URL and try again?</h2><p>And if it doesn't work, <a href='https://github.com/tabulapdf/tabula/issues/new'> report a bug</a> and explain <em>exactly</em> what steps you took that caused this problem\");\n        }),\n      });\n    },\n\n    checkForAutodetectedTables: function(){\n      this.pdf_document.autodetected_selections.fetch({\n        success: _.bind(function(){\n          this.hasAutodetectedTables = true;\n          window.clearTimeout(this.autodetect_timer);\n          this.render();\n        }, this),\n        error: _.bind(function(){\n          console.log(\"no predetected tables (404 on tables.json)\");\n          this.autodetect_timer = window.setTimeout(this.checkForAutodetectedTables, 2000);\n          this.render();\n        }, this)\n      });\n    },\n\n    renderSelection: function(sel){\n      // for a Tabula.Selection object's toCoords output (presumably taken out of the selection collection)\n      // cause it to be rendered onto the page, and as a thumbnail\n      // and causes it to get an 'id' attr.\n      console.log(\"sel.page\", sel);\n      var pageView = Tabula.pdf_view.components['document_view'].page_views[sel.page];\n      var page = Tabula.pdf_view.pdf_document.page_collection.findWhere({number: sel.page});\n      if(!page){\n        // the page we're trying to render a selection on might have been deleted.\n        // or, we may be trying to load a template with more pages on it than this PDF has.\n        console.log(\"can't render selection on page \" + sel.page + \" because that page can't be found\", sel)\n        return;\n      }\n      var original_pdf_width = page.get('width');\n      var original_pdf_height = page.get('height');\n      // var pdf_rotation = page.get('rotation');\n\n      // TODO: create selection models for pages that aren't lazyloaded, but obviously don't display them.\n      if(Tabula.LazyLoad && !pageView){\n        return [];\n      }\n\n      // mimics drawing the selection onto the page\n      var $img = pageView.$el.find('img');\n      var image_width = $img.width();\n      if (!$img.length || $img.data('loaded') !== 'loaded' || !$img.height() ){ // if this page isn't shown currently or the image hasn't been rendered yet, then create a hidden selectionx\n        return this.pdf_document.selections.createHiddenSelection(sel);\n      }\n      var scale = image_width / original_pdf_width;\n      var offset = $img.offset();\n      var absolutePos = _.extend({}, offset,\n                                {\n                                  'top':  offset.top + (sel.y1 * scale),\n                                  'left': offset.left + (sel.x1 * scale),\n                                  'width': (sel.width * scale),\n                                  'height': (sel.height * scale)\n                                });\n      // TODO: refactor to only have this ResizableSelection logic in one place.\n      var vendorSelection = new ResizableSelection({\n        position: absolutePos,\n        target: pageView.$el.find('img'),\n        areas: function(){ return Tabula.pdf_view.components['document_view']._selectionsGetter($img) }\n      });\n      vendorSelection.on({\n        resize: _.debounce(pageView._onSelectChange, 100),\n        remove: pageView._onSelectCancel\n      });\n\n      Tabula.pdf_view.components['document_view'].$el.append(vendorSelection.el);\n\n      pageView._onSelectEnd(vendorSelection); // draws the thumbnail\n\n      // put the selection into the selections collection\n      selection = this.pdf_document.selections.updateOrCreateByVendorSelectorId(vendorSelection, sel.page, image_width);\n      return selection;\n\n    },\n\n    removePage: function(removedPageModel){\n      $.post((base_uri || '/') + 'pdf/' + PDF_ID + '/page/' + removedPageModel.get('number'),\n           { _method: 'delete' },\n           function () {\n               Tabula.pdf_view.pageCount -= 1;\n           });\n\n      // removing the views is handled by the views themselves.\n\n      //remove selections\n      var selections = this.pdf_document.selections.where({page_number: removedPageModel.get('number')});\n      this.pdf_document.selections.remove(selections);\n    },\n\n    createDataView: function(){\n      this.components['data_view'] = new Tabula.DataView({pdf_view: this, model: Tabula.pdf_view.query});\n    },\n\n    addOne: function(page) {\n      if(page.get('deleted')){\n        return;\n      }\n      var page_view = new Tabula.PageView({model: page, collection: this.pdf_document.page_collection});\n      var thumbnail_view = new Tabula.ThumbnailView({model: page, collection: this.pdf_document.page_collection});\n\n\n      this.components['document_view'].page_views[ page.get('number') ] =  page_view;\n      this.components['sidebar_view'].thumbnail_list_view.thumbnail_views[ page.get('number') ] = thumbnail_view;\n    },\n\n    addAll: function() {\n      // a failed attempt at lazy load. kept in case I change my mind.\n      // if(Tabula.LazyLoad){\n      //   _(this.pdf_document.page_collection.slice(0, Tabula.LazyLoad)).each(this.addOne, this);\n      // }else{\n        this.pdf_document.page_collection.each(this.addOne, this);\n      // }\n    },\n\n    totalSelections: function() {\n      return this.pdf_document.selections.size();\n    },\n\n    loadSavedTemplate: function(template_model){\n      var existent_page_numbers = Tabula.pdf_view.pdf_document.page_collection.models.map(function(page){ return page.get('number')});\n\n      _(Tabula.pdf_view.pdf_document.selections.models.slice()).each(function(i){ if(typeof i.attributes.remove !== \"undefined\") i.attributes.remove(); }); // call remove() on the vendorSelection of each seleciton; except for \"hidden\" selections that don't have one.\n      template_model.fetch({success: _.bind(function(template_model){\n        var selections_to_load = _(_(template_model.get('selections')).filter(function(sel){ return existent_page_numbers.indexOf(sel.page) >= 0 })).map(function(sel){\n          return Tabula.pdf_view.renderSelection(sel);\n        });\n        this.pdf_document.selections.reset(selections_to_load);\n      }, this)});\n    },\n\n    saveTemplate: function (cb) {\n      var name = (this.loadedSavedState && this.loadedSavedState.name) || (this.pdf_document.attributes.original_filename).replace(\".pdf\", \"\")\n      console.log(this.pdf_document.attributes);\n      this.saveTemplateAs(null, name, cb)\n    },\n\n    saveTemplateAs: function(id, name, cb){\n      var list_of_coords = Tabula.pdf_view.pdf_document.selections.invoke(\"toCoords\");\n      // {\"name\": \"fake test template\", \"selection_count\": 0, \"page_count\": 0, \"time\": \"1499535056\", \"id\": \"asdfasdf\"}\n      var templateMetadata = {\n        name: name,\n        selection_count: list_of_coords.length,\n        page_count: _(_(list_of_coords).map(function(obj){ return obj[\"page\"] })).uniq().length,\n        time: Math.floor(Date.now() / 1000),\n        template: _(list_of_coords).map(function(obj){ return _.omit(obj, 'selection_id') })\n      };\n      var saved_template = new Tabula.SavedTemplate(templateMetadata);\n      saved_template.save(null,{success: cb, error: cb});\n    },\n\n    render : function(){\n      document.title=\"Select Tables | Tabula\";\n      this.components['document_view'].render();\n\n      $('#control-panel').append(this.components['control_panel'].render().el);\n      $('#sidebar').append(this.components['sidebar_view'].render().el);\n      this.components['sidebar_view'].thumbnail_list_view.$el = this.components['sidebar_view'].$el.find(\"#thumbnail-list\");\n      this.components['sidebar_view'].thumbnail_list_view.render();\n\n      $('.has-tooltip').tooltip();\n\n      this.pageCount = this.pdf_document.page_collection.size();\n\n      // an attempt to restore the scroll position when you return to revise selections\n      // I'm not sure why it doesn't work without a timeout -- maybe because the images haven't rendered yet?\n      if(this.selectionScrollTop){\n        $('html').scrollTop(this.selectionScrollTop);\n        this.selectionScrollTop = 0;\n      }\n\n      return this;\n    },\n  }, Tabula.DebugPDFView));\n\n\nTabula.SavedTemplateView = Backbone.View.extend({\n  tagName: 'li',\n  className: 'saved-template',\n  events: {\n    'click a': 'loadTemplate'\n  },\n  template: _.template(\"<a><%= name %></a>\"),\n  initialize: function(){\n    _.bindAll(this, 'render', 'loadTemplate');\n  },\n  render: function(){\n    this.$el.append(this.template(this.model.attributes));\n    this.$el.addClass('file-id-' + this.model.get('id')); // more efficient lookups than data-attr\n    if(Tabula.pdf_view.totalSelections() > 0){\n      this.$el.find(\"a\").attr(\"disabled\", \"disabled\");\n      this.$el.find(\"a\").css({\"color\": \"gray\", \"cursor\": \"default\"})\n    }\n    this.$el.data('id', this.model.get('id')); //more cleanly accesse than a class\n    return this;\n  },\n  loadTemplate: function(e){\n    if($(e.currentTarget).attr(\"disabled\")){\n      return;\n    }\n    Tabula.pdf_view.loadSavedTemplate(this.model); // TODO: make this not a reference to global Tabula.pdf_view\n  }\n});\nTabula.SavedTemplateLibraryView = Backbone.View.extend({\n  tagName: 'ul',\n  initialize: function(stuff){\n    _.bindAll(this, 'render');\n    this.listenTo(this.collection, 'change', this.render);\n  },\n  render: function(){\n    this.$el.empty();\n    this.collection.each(_.bind(function(saved_template_model){\n      var template_view = new Tabula.SavedTemplateView({model: saved_template_model, collection: this.collection});\n      this.$el.append(template_view.render().el);\n    }, this));\n    return this;\n  }\n});\n\n\n\nfunction isElementPartiallyInViewport (el) {\n  if (el instanceof jQuery) {\n      el = el[0];\n  }\n  var rect = el.getBoundingClientRect();\n  return (\n      ( (rect.top > 0 && rect.top < (window.innerHeight || document.documentElement.clientHeight) ) ||\n      (rect.bottom < (window.innerHeight || document.documentElement.clientHeight) && rect.bottom > 0) ) && /*or $(window).height() */\n      ( (rect.left > 0 && rect.left < (window.innerWidth || document.documentElement.clientWidth) ) ||\n      (rect.right < (window.innerWidth || document.documentElement.clientWidth) && rect.right > 0) ) /*or $(window).height() */\n  );\n}\n\n\n// checks if el is overlaps the overlaps the visible portion of the container\nfunction isElementPartiallyInContainer (el, container) {\n  if (el instanceof jQuery) {\n      el = el[0];\n  }\n  if (container instanceof jQuery) {\n      container = container[0];\n  }\n  var rect = el.getBoundingClientRect();\n  var container_rect = container.getBoundingClientRect();\n  var bounding_rect = {}; // the intersection of the viewport and the container\n  bounding_rect.top = Math.max(container_rect.top, 0);\n  bounding_rect.left = Math.max(container_rect.left, 0);\n  bounding_rect.bottom = Math.min(container_rect.bottom, (window.innerHeight || document.documentElement.clientHeight));\n  bounding_rect.right = Math.min(container_rect.right, (window.innerWidth || document.documentElement.clientWidth));\n\n  return (\n      ( (rect.top >= bounding_rect.top && rect.top <= (bounding_rect.bottom) ) ||\n      (rect.bottom <= (bounding_rect.bottom) && rect.bottom >= bounding_rect.top) ) &&\n      ( (rect.left >= bounding_rect.left && rect.left <= (bounding_rect.right) ) ||\n      (rect.right <= (bounding_rect.right) && rect.right >= bounding_rect.left) )\n  );\n}\n\n\n\nfunction isElementInViewport (el) {\n  if (el instanceof jQuery) {\n      el = el[0];\n  }\n\n  var rect = el.getBoundingClientRect();\n\n  return (\n      rect.top >= 0 &&\n      rect.left >= 0 &&\n      rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */\n      rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */\n  );\n}\n\nfunction roundTo(num, fancymathwordforthenumberofdigitsafterthedecimal){\n  return Math.round(num * Math.pow(10, fancymathwordforthenumberofdigitsafterthedecimal)) / Math.pow(10, fancymathwordforthenumberofdigitsafterthedecimal);\n}\n"
  },
  {
    "path": "webapp/static/js/rectangularSelector.js",
    "content": "/* jshint undef: true, unused: true */\n/* global $, _, console, document */\n\n(function (name, context, definition) {\n  if (typeof module != 'undefined' && module.exports) module.exports = definition();\n  else if (typeof define == 'function' && define.amd) define(definition);\n  else context[name] = definition();\n})('RectangularSelector', this, function (name, context) {\n\n  // returns true if rect does not overlap with at least one of the otherRects\n  var checkOverlaps = function(rect, otherRects) {\n    if (otherRects.length === 0) return true;\n    return _.every(\n      otherRects,\n      function(or) {\n        if(!or) return false;\n        or = or.getDims().absolutePos;\n        return rect.left + rect.width < or.left ||\n          or.left + or.width < rect.left ||\n          rect.top + rect.height < or.top ||\n          or.top + or.height < rect.top;\n      }\n    );\n  };\n\n  var rectangularSelector = function(pdfListView, options) {\n    var isDragging = false;\n    var target = null;\n    var start = null;\n    var options = _.extend({\n      selector: options.selector || 'div.page-view canvas',\n      validSelection: function(selection) { return true; },\n      start: function() {},\n      end: function() {},\n      drag: function() {},\n      areas: []\n    }, options);\n    var fullSelector = options.selector + ', .selection-box';\n    var self = this;\n    this.box = $('<div></div>').addClass('selection-box').appendTo($('body'));\n\n    var _mousedown = function(event) {\n      if (event.which !== 1) return false;\n      target = this;\n      isDragging = true;\n      start = { x: event.pageX, y: event.pageY };\n      self.box.css({\n        'top': start.y,\n        'left': start.x,\n        'width': 0,\n        'height': 0,\n        'visibility': 'visible'\n      });\n      options.start(event);\n      return false;\n    };\n\n    var _mousemove = function(event) {\n      if (!isDragging || ($(event.target).is(options.selector) && event.target !== target)) {\n        return;\n      }\n      var ds = {\n        'left': Math.min(start.x, event.pageX),\n        'top': Math.min(start.y, event.pageY),\n        'width': Math.abs(start.x - event.pageX),\n        'height': Math.abs(start.y - event.pageY)\n      };\n\n      if (checkOverlaps(ds,\n                        _.values(\n                          _.isFunction(options.areas) ? options.areas(target) : options.areas)\n                       )\n         ) {\n        self.box.css(ds);\n        options.drag(ds);\n      }\n    };\n\n    var _mouseup = function(event) {\n      if (isDragging) { // selection ended\n        if (event.which !== 1) return;\n        var targetPageView, allTargets = $(options.selector);\n\n        for (var i = 0; i < allTargets.length; i++) {\n          if (allTargets.get(i) === target) {\n            targetPageView = allTargets.get(i);\n            break;\n          }\n        }\n\n        var cOffset = $(target).offset(),\n            top = parseFloat(self.box.css('top')),\n            left = parseFloat(self.box.css('left')),\n            width = parseFloat(self.box.css('width')),\n            height = parseFloat(self.box.css('height'));\n\n        var d = {\n          'absolutePos': _.extend(cOffset,\n                                  {\n                                    'top': top,\n                                    'left': left,\n                                    'width': width,\n                                    'height': height\n                                  }),\n          'relativePos': {\n            'width': width,\n            'height': height,\n            'top': top - cOffset.top,\n            'left': left - cOffset.left\n          },\n          'pageView': targetPageView\n        };\n        if (options.validSelection(d)) {\n          options.end(d);\n        }\n\n      }\n      target = null;\n      start = null;\n      isDragging = false;\n      self.box.css('visibility', 'hidden');\n    };\n\n    $(document).on({\n      mousedown: _mousedown,\n      mousemove: _mousemove,\n      mouseup: _mouseup\n    }, fullSelector);\n\n    // global mouseup listener so we can end the selection\n    // if the user mouseups outside the target area\n    $(document).on('mouseup', _mouseup);\n  };\n\n  return rectangularSelector;\n\n});\n"
  },
  {
    "path": "webapp/static/js/resizableSelection.js",
    "content": "/* jshint undef: true, unused: true */\n/* global $, paper, Backbone, _, console */\n\n(function (name, context, definition) {\n  if (typeof module != 'undefined' && module.exports) module.exports = definition();\n  else if (typeof define == 'function' && define.amd) define(definition);\n  else context[name] = definition();\n})('ResizableSelection', this, function (name, context) {\n\n\n  var resizeDirectionMatch = /(n|s|w|e|ne|nw|se|sw)-border/;\n\n  var ResizableSelection = Backbone.View.extend({\n\n    tagName: 'div',\n    className: 'table-region',\n\n    events: {\n      'mousedown .resize-handle': 'mouseDownResize',\n      'mousemove': 'mouseMoveResize',\n      'mouseup': 'mouseUpResize',\n      'click button[name=close]': 'remove'\n    },\n\n    template:\n    \"<div class='resize-handle n-border'></div>\" +\n      \"<div class='resize-handle s-border'></div>\" +\n      \"<div class='resize-handle w-border'></div>\" +\n      \"<div class='resize-handle e-border'></div>\" +\n      \"<div class='resize-handle nw-border'></div>\" +\n      \"<div class='resize-handle sw-border'></div>\" +\n      \"<div class='resize-handle se-border'></div>\" +\n      \"<div class='resize-handle ne-border'></div>\" +\n      \"<button name='close'>×</button>\",\n\n    initialize: function(options) {\n      this.bounds = options.bounds;\n      this.pageView = options.target;\n      this.areas = options.areas;\n\n      this.id = String.fromCharCode(65 + Math.floor(Math.random() * 26)) + Date.now();\n\n      this.render();\n      this.$el.css(options.position);\n\n      $(options.target).on({\n        mousemove: _.bind(this.mouseMoveResize, this),\n        mouseup: _.bind(this.mouseUpResize, this)\n      });\n\n      /* like rectangularSelector, we need to bind a global event\n       * to watch if the user mouses-up outside the target element. */\n       $(document).on({\n         mouseup: _.bind(this.mouseUpResize, this)\n       });\n    },\n\n    render: function() {\n      this.$el.append(this.template);\n      return this;\n    },\n\n    remove: function() {\n      this.trigger('remove', this);\n      Backbone.View.prototype.remove.call(this);\n    },\n\n\n    getDims: function() {\n      if((!$(this.pageView).is(':visible') || !this.$el.is(':visible')) && this.cachedDims){\n        return this.cachedDims;\n      }\n      var o = { top: parseFloat(this.$el.css('top')),\n                left: parseFloat(this.$el.css('left')) };\n      var targetPos = $(this.pageView).offset();\n      // console.log($(this.pageView).is(':visible'), this.$el.is(':visible'));\n      this.cachedDims = {\n        id: this.id,\n        \"$el\": this.$el,\n        absolutePos: {\n          top: o.top,\n          left: o.left,\n          width: this.$el.css('box-sizing') == \"border-box\" ? this.$el.outerWidth() : this.$el.width(),\n          height: this.$el.css('box-sizing') == \"border-box\" ? this.$el.outerHeight(): this.$el.height()\n        },\n        relativePos: {\n          top: o.top - targetPos.top,\n          left: o.left - targetPos.left,\n          width: this.$el.css('box-sizing') == \"border-box\" ? this.$el.outerWidth() : this.$el.width(),\n          height: this.$el.css('box-sizing') == \"border-box\" ? this.$el.outerHeight() : this.$el.height()\n        }\n      };\n      return this.cachedDims;\n    },\n\n    mouseDownResize: function(event) {\n      var d = resizeDirectionMatch.exec($(event.target).attr('class'));\n      if (!d || d.length < 2) {\n        this.resizing = false;\n      }\n      else {\n        this.resizing = d[1];\n        this.trigger('start', this);\n      }\n    },\n\n    mouseMoveResize: function(event) {\n      if (!this.resizing) return;\n      var ev = event;\n      var css = {};\n      var oldDims = this.getDims().absolutePos;\n\n      if (this.resizing.indexOf('n') !== -1) {\n        css.height = oldDims.height + oldDims.top - ev.pageY;\n        css.top = ev.pageY;\n      }\n      else if (this.resizing.indexOf('s') !== -1) {\n        css.height = ev.pageY - oldDims.top;\n      }\n\n      if (this.resizing.indexOf('w') !== -1) {\n        css.width =  oldDims.width + oldDims.left - ev.pageX;\n        css.left = ev.pageX;\n      }\n      else if (this.resizing.indexOf('e') !== -1) {\n        css.width = ev.pageX - oldDims.left;\n      }\n\n      this.$el.css(css);\n      this.trigger('resize', this.getDims());\n      if (!this.checkOverlaps()) {\n        this.$el.css(oldDims);\n      }\n    },\n\n    mouseUpResize: function(event) {\n      if (this.resizing) {\n        this.trigger('resize', this.getDims());\n      }\n      this.resizing = false;\n    },\n\n    // returns true if this tableView does not overlap\n    // with any other on the same page\n    checkOverlaps: function() {\n      var thisDims = this.getDims().absolutePos;\n      return _.every(\n        _.reject(this.areas(this.pageView), function(s) {\n          return s.id === this.id;\n        }, this),\n        function(s) {\n          var sDims = s.getDims().absolutePos;\n          return thisDims.left + thisDims.width < sDims.left ||\n            sDims.left + sDims.width < thisDims.left ||\n            thisDims.top + thisDims.height < sDims.top ||\n            sDims.top + sDims.height < thisDims.top;\n        }, this);\n    }\n  });\n\n  return ResizableSelection;\n});\n"
  },
  {
    "path": "webapp/static/js/tabula.js",
    "content": "var Tabula;\nwindow.Tabula = Tabula || {};\n$.ajaxSetup({ cache: false }); // fixes a dumb issue where Internet Explorer caches Ajax requests. See https://github.com/tabulapdf/tabula/issues/408\nvar base_uri = $('base').attr(\"href\");\n\nTabula.UI_VERSION = \"1.2.1-2018-05-22\"; // when we make releases, we should remember to up this.\n// Add '-pre' to the end of this for a prerelease version; this will let\n// our \"new version\" check give you that channel.\n\n// Note that this is separate from the \"API version\" (internal app version)\n// which is what we check against GitHub. In the future, this will allow us\n// to modularize the UI from the backend some more.\n\n\nvar TabulaRouter = Backbone.Router.extend({\n  routes: {\n    \"\":                            \"upload\",\n    \"/\":                           \"upload\",\n    \"pdf/:file_id\":                \"view\",\n    \"pdf/:file_id/extract\":        \"view\", // you have to make selections first, so going directly to /extract doesn't work.\n    \"queue/:file_id\":              'status',\n    \"error\":                       'uploadError',\n    \"help\":                        'help',\n    \"about\":                       'about',\n    \"mytemplates\":                 'templates'\n  },\n\n  help: function(){\n    document.title=\"Help | Tabula\";\n    $('nav li a').removeClass('active'); $('nav #help-nav').addClass('active');\n    $('#tabula-app').html( _.template( $('#help-template').html().replace(/nestedscript/g, 'script') )({ }) );\n  },\n\n  about: function(){\n    document.title=\"About | Tabula\";\n    $('nav li a').removeClass('active'); $('nav #about-nav').addClass('active');\n    $('#tabula-app').html( _.template( $('#about-template').html().replace(/nestedscript/g, 'script') )({ }) );\n  },\n\n  templates: function(){\n    document.title=\"Templates | Tabula\";\n    $('nav li a').removeClass('active'); $('nav #templates-nav').addClass('active');\n    $('#tabula-app').html( _.template( $('#templates-template').html().replace(/nestedscript/g, 'script') )({ }) );\n    $.ajax({\n      url: (base_uri || '/') + \"js/template_library.js\",\n      dataType: \"script\",\n      async: true,\n      success: function(data, status, jqxhr){\n        Tabula.library = new Tabula.TemplateLibrary({el: $('#tabula-app')[0]}).render();\n      },\n      error: function(a,b,c){\n        console.log(a,b,c);\n      }\n    });\n  },\n\n  upload: function() { // library page.\n    document.title=\"Import | Tabula\";\n    $('nav li a').removeClass('active'); $('nav #upload-nav').addClass('active');\n    $.ajax({\n      url: (base_uri || '/') + \"js/library.js\",\n      dataType: \"script\",\n      async: true,\n      success: function(data, status, jqxhr){\n        Tabula.library = new Tabula.Library({el: $('#tabula-app')[0]}).render();\n      },\n      error: function(a,b,c){\n        console.log(a,b,c);\n      }\n    });\n  },\n\n  view: function(file_id) {\n    $('nav li a').removeClass('active');\n    // $('body').prepend( _.template( $('#navbar-template').html().replace(/nestedscript/g, 'script') )({}) ); // navbar.\n    $('body').addClass('page-selections')\n    $('#tabula-app').html( _.template( $('#pdf-view-template').html().replace(/nestedscript/g, 'script') )({}) );\n\n    $.ajax({\n      url: (base_uri || '/') + \"js/pdf_view.js\",\n      dataType: \"script\",\n      async: true,\n      success: function(data, status, jqxhr){\n        Tabula.pdf_view = new Tabula.PDFView({pdf_id: file_id});\n        Tabula.pdf_view.getData();\n      },\n      error: function(a,b,c){\n        console.log(a,b,c);\n      }\n    });\n  },\n});\n\n\nTabula.getSettings = function(){\n\n  Tabula.notification = new Backbone.Model({});\n  Tabula.new_version = new Backbone.Model({});\n  $.getJSON((base_uri || '/') + \"settings\", function(data){\n\n    // there are two ways to turn off notifications: \n    // 1. in settings.rb (which is set via command-line options) and in which you can turn off one\n    //    but not the other.\n    // 2. in localStorage.\n\n    // on first usage, we do nothing. once you've seen the opt-out banner,\n    // we continue to show it, but fetch notifications.\n\n    getNotifications = function(){\n      if(data[\"disable_version_check\"] === false) {\n        Tabula.getLatestReleaseVersion();\n      }\n      if(data[\"disable_notifications\"] === false) {\n        Tabula.getNotifications();\n      }\n    }\n\n    var notificationsDialogSeen = localStorage.getItem(\"tabula-notifications-dialog-seen\");\n    var acceptsNotifications = localStorage.getItem(\"tabula-notifications\");\n    if (acceptsNotifications == \"true\"){\n      getNotifications();\n    }else if (acceptsNotifications == \"false\"){\n     // do nothing.\n    }else{ // null or unset\n      if (notificationsDialogSeen){\n        getNotifications();\n      }else{\n        localStorage.setItem(\"tabula-notifications-dialog-seen\", true);\n      }\n      $('#tabula-app').after( _.template( $('#notifications-approval-template').html().replace(/nestedscript/g, 'script') )({ }) );\n      $('#notifications-approval-clicky #notifications-approval-close, #notifications-approval-clicky #notifications-approval-okay').on(\"click\", function(){\n        localStorage.setItem(\"tabula-notifications-dialog-seen\", true);\n        localStorage.setItem(\"tabula-notifications\", true);\n        $('#notifications-approval-clicky').hide();\n      })\n      $('#notifications-approval-clicky #notifications-approval-opt-out').on(\"click\", function(){\n        localStorage.setItem(\"tabula-notifications-dialog-seen\", true);\n        localStorage.setItem(\"tabula-notifications\", false);\n        $('#notifications-approval-clicky').hide();\n      })\n    }\n    Tabula.api_version = data[\"api_version\"];\n    if(Tabula.api_version.slice(0,3) == \"rev\"){\n      // $('#dev-mode-ribbon').show();\n      console.log(\"This is a development version of Tabula!\")\n    }\n\n  })\n}\n\n\nTabula.getLatestReleaseVersion = function(){\n  $.get('https://api.github.com/repos/tabulapdf/tabula/releases',\n      function(data) {\n        if (data.length < 1) return;\n        if (Tabula.api_version.indexOf('rev') == 0) return;\n\n        var prerelease = (Tabula.UI_VERSION.indexOf(\"-pre\") !== -1);\n        if (prerelease) {console.log(\"Is prerelease\");}\n\n        // check if new version\n        var non_prerelease_i = 0;\n        for (var i=0; i<data.length; i++) {\n          var d = data[i];\n          if (!!d.draft) { continue; } // ignore drafts\n          if (!prerelease && !!d.prerelease) { continue; } // ignore prereleases unless we're on a prerelease\n\n          var rel_ver_re = /\\((\\d+\\.\\d+\\.\\d+\\.\\d+)\\)/;\n          console.log(\"checking \" + d.name + \" vs \" + Tabula.api_version);\n\n          // Either the name of the GitHub release is the the version or the\n          // name of the GitHub release contains the full 4-part \"build id\"\n          // in parenthesis.\n          //   * \"1.1.0\"\n          //   * \"Tabula 1.1.0 Release (1.1.0.16091701)\" (YYMMDDxx, with xx as a day-based serial number in case we need it)\n          if ((non_prerelease_i === 0) && (\n            (d.name == Tabula.api_version) ||\n            (!!d.name.match(rel_ver_re) && (d.name.match(rel_ver_re)[1] === Tabula.api_version))\n          )) {\n            // if index == 0, current release is the newest, so break out of this fn\n            console.log(\" -> IS LATEST\");\n            return;\n          } else {\n            // keep iterating, maybe we'll find this version later in list\n            non_prerelease_i += 1;\n          }\n        }\n\n        // We're not the latest release, grab data from GitHub & tell user\n        var new_release = data[0];\n        if(new_release){\n          Tabula.new_version.set(new_release);\n        }\n      }\n  );\n};\n\n\nTabula.getNotifications = function(){\n  $.ajax({\n    url: 'http://tabula.jeremybmerrill.com/tabula/notifications.jsonp',\n    dataType: \"jsonp\",\n    jsonpCallback: 'notifications',\n    success: function(data){\n      if(data.length < 1) return;\n\n      // find the first listed notification where today is between its `live_date` and `expires_date`\n      // and within the `versions` list.\n      // we might use this for, say, notifying users if a version urgently needs an update or something\n      var notifications = $.grep(data, function(d){\n        var today = new Date();\n        if ( (d.expires_date && (new Date(d.expires_date) < today)) || (d.live_date && (new Date(d.live_date) > today)) ){\n          return false;\n        }\n        if( d.versions && d.versions.length > 0){\n          return (d.versions.indexOf(Tabula.api_version) > -1);\n        }else{\n          return true;\n        }\n      });\n\n      if(notifications.length >= 1){\n        console.log(notifications.length + \" matching notifications:\", notifications);\n        Tabula.notification.set(notifications[0]);\n      }else{\n        console.log(\"no notifications\")\n      }\n    }});\n}\n\n\n\n$(function(){\n  Tabula.getSettings();\n  window.tabula_router = new TabulaRouter();\n  Backbone.history.start({\n    pushState: true,\n    root: base_uri\n  });\n});\n"
  },
  {
    "path": "webapp/static/js/template_library.js",
    "content": "Backbone.emulateJSON = true;\nTabula.SavedTemplate = Backbone.Model.extend({\n  // templates.push({\"name\": \"fake test template\", \"selection_count\": 0, \"page_count\": 0, \"time\": \"1499535056\", \"id\": \"asdfasdf\"})\n  name: null,\n  page_count: null,\n  selection_count: null,\n  id: null,\n  time: 0,\n  urlRoot: \"templates\",\n  initialize: function(){\n    this.set('name', this.get('name') || null);\n    this.set('page_count', this.get('page_count') || null)\n    this.set('selection_count', this.get('selection_count') || null)\n    this.set('id', this.get('id') || null)\n    this.set('time', this.get('time') || null)\n  }\n});\n\nTabula.TemplatesCollection = Backbone.Collection.extend({\n    model: Tabula.SavedTemplate,\n    url: \"templates\",\n    comparator: function(i){ return -i.get('time')}\n});\n\nTabula.SavedTemplateView = Backbone.View.extend({\n  tagName: 'tr',\n  className: 'saved-template',\n  events: {\n    'click .delete-template': 'deleteTemplate',\n    'click .download-template': 'downloadTemplate',\n    'click .edit-template-name': 'editTemplateName',\n    'click .save-template-name': 'renameTemplate'\n  },\n  template: _.template( $('#saved-template-library-item-template').html().replace(/nestedscript/g, 'script')),\n  initialize: function(){\n    _.bindAll(this, 'render', 'deleteTemplate', 'renameTemplate', 'editTemplateName');\n  },\n  render: function(){\n    this.$el.append(this.template(this.model.attributes));\n    this.$el.addClass('saved-template-id-' + this.model.get('id')); // more efficient lookups than data-attr\n    this.$el.data('id', this.model.get('id')); //more cleanly accessed than a class\n    return this;\n  },\n  editTemplateName: function(e) {\n    var name_el = this.$el.find(\".template-name\");\n    $(name_el).replaceWith($('<input type=\"text\" value=\"'+this.model.get('name')+'\">'));\n    $(e.currentTarget).replaceWith($(\"<a href=\\\"javascript:\\\"><span class=\\\"glyphicon glyphicon-floppy-disk save-template-name\\\"></span></a>\"));\n  },\n  renameTemplate: function(e){\n    var input_el = $(e.currentTarget).closest(\"td\").find(\"input\");\n    var new_name = input_el.val();\n    this.model.set({'name': new_name});\n    this.model.save();\n    $(input_el).replaceWith($('<span class=\"template-name\">'+this.model.get('name')+'</span>'));\n    $(e.currentTarget).replaceWith($('<a href=\"javascript:\"><span class=\"glyphicon glyphicon-pencil edit-template-name\"></span></a>'));\n\n  },\n  downloadTemplate: function(e) {\n    // no-op, this is handled old-school by a form element. No javascript, no jquery, certainly no backbone involved.\n  },\n  deleteTemplate: function(e) {\n    var template_id = $(e.currentTarget).data(\"id\");\n    // var btn = $(e.currentTarget);\n    // var tr = btn.parents('tr');\n\n    // if (!confirm('Delete file \"'+btn.data('filename')+'\"?')) return;\n    // var pdf_id = btn.data('pdfid');\n    this.model.destroy({success: _.bind(function() {\n            this.$el.fadeOut(200, function() { $(this).remove(); });\n          }, this)});\n    }\n})\n\n\n\nTabula.TemplateLibrary = Backbone.View.extend({\n    events: {\n        \"submit form#uploadtemplate\": 'uploadTemplate',\n    },\n\n    initialize: function(){\n      _.bindAll(this, 'uploadTemplate', 'renderTemplateLibrary');\n      this.templates_collection = new Tabula.TemplatesCollection([]);\n      this.templates_collection.fetch({silent: true, complete: _.bind(function(){ this.render(); }, this) });\n      this.listenTo(this.templates_collection, 'add', this.renderTemplateLibrary);\n      this.templates_collection.fetch() // {complete: _.bind(function(){ this.renderTemplateLibrary(); }, this)});\n      this.render();\n    },\n    uploadTemplate: function(e){\n      $(e.currentTarget).find('button').attr('disabled', 'disabled');\n\n      var formdata = new FormData($('form#uploadtemplate')[0]);\n      $.ajax({\n          url: $('form#uploadtemplate').attr('action'),\n          type: 'POST',\n          success: _.bind(function (res) {\n            $(e.currentTarget).find('button').removeAttr('disabled');\n            $('form#uploadtemplate')[0].reset();\n            this.templates_collection.fetch();\n          }, this),\n          error: _.bind(function(a,b,c){\n            alert('error in uploading template!')\n            console.log(\"error in uploading template\",a,b,c);\n            $(e.currentTarget).find('button').removeAttr('disabled');\n          },this),\n          data: formdata,\n\n          cache: false,\n          contentType: false,\n          processData: false\n      });\n      e.preventDefault();\n      return false; // don't actually submit the form\n    },\n\n    renderTemplateLibrary: function(added_model){\n      console.log(\"renderTemplateLibrary\", added_model);\n      if(this.templates_collection.length > 0){\n        $('#template-library-container').show();\n        var templates_table = this.$el.find('#saved-templates-container')\n\n        templates_table.empty();\n\n        this.templates_collection.each(_.bind(function(template, i){\n          var template_element = new Tabula.SavedTemplateView({model: template}).render().$el;\n          if(added_model && added_model.get('id') == template.get('id')){\n            template_element.addClass('flash');\n          }\n          templates_table.append(template_element);\n        }, this));\n\n        var table_for_sorting = $('#templateTable');\n        if(table_for_sorting.hasClass(\"tablesorter\")){\n          table_for_sorting.trigger('update');\n        }else{\n         table_for_sorting.addClass('tablesorter');\n         table_for_sorting.tablesorter( {\n            headers: { 3: { sorter: \"usLongDate\" },  4: { sorter: false}, 5: {sorter: false} },\n            sortList: [[3,1]]  // initial sort\n            } );\n        }\n      }else{\n        $('#template-library-container').hide();\n      }\n    },\n    render: function(){\n      $('#tabula-app').html();\n      this.renderTemplateLibrary();\n      return this;\n    }\n});"
  },
  {
    "path": "webapp/static/js/vendor/backbone-min.js",
    "content": "(function(t,e){if(typeof define===\"function\"&&define.amd){define([\"underscore\",\"jquery\",\"exports\"],function(i,r,s){t.Backbone=e(t,s,i,r)})}else if(typeof exports!==\"undefined\"){var i=require(\"underscore\");e(t,exports,i)}else{t.Backbone=e(t,{},t._,t.jQuery||t.Zepto||t.ender||t.$)}})(this,function(t,e,i,r){var s=t.Backbone;var n=[];var a=n.push;var o=n.slice;var h=n.splice;e.VERSION=\"1.1.2\";e.$=r;e.noConflict=function(){t.Backbone=s;return this};e.emulateHTTP=false;e.emulateJSON=false;var u=e.Events={on:function(t,e,i){if(!c(this,\"on\",t,[e,i])||!e)return this;this._events||(this._events={});var r=this._events[t]||(this._events[t]=[]);r.push({callback:e,context:i,ctx:i||this});return this},once:function(t,e,r){if(!c(this,\"once\",t,[e,r])||!e)return this;var s=this;var n=i.once(function(){s.off(t,n);e.apply(this,arguments)});n._callback=e;return this.on(t,n,r)},off:function(t,e,r){var s,n,a,o,h,u,l,f;if(!this._events||!c(this,\"off\",t,[e,r]))return this;if(!t&&!e&&!r){this._events=void 0;return this}o=t?[t]:i.keys(this._events);for(h=0,u=o.length;h<u;h++){t=o[h];if(a=this._events[t]){this._events[t]=s=[];if(e||r){for(l=0,f=a.length;l<f;l++){n=a[l];if(e&&e!==n.callback&&e!==n.callback._callback||r&&r!==n.context){s.push(n)}}}if(!s.length)delete this._events[t]}}return this},trigger:function(t){if(!this._events)return this;var e=o.call(arguments,1);if(!c(this,\"trigger\",t,e))return this;var i=this._events[t];var r=this._events.all;if(i)f(i,e);if(r)f(r,arguments);return this},stopListening:function(t,e,r){var s=this._listeningTo;if(!s)return this;var n=!e&&!r;if(!r&&typeof e===\"object\")r=this;if(t)(s={})[t._listenId]=t;for(var a in s){t=s[a];t.off(e,r,this);if(n||i.isEmpty(t._events))delete this._listeningTo[a]}return this}};var l=/\\s+/;var c=function(t,e,i,r){if(!i)return true;if(typeof i===\"object\"){for(var s in i){t[e].apply(t,[s,i[s]].concat(r))}return false}if(l.test(i)){var n=i.split(l);for(var a=0,o=n.length;a<o;a++){t[e].apply(t,[n[a]].concat(r))}return false}return true};var f=function(t,e){var i,r=-1,s=t.length,n=e[0],a=e[1],o=e[2];switch(e.length){case 0:while(++r<s)(i=t[r]).callback.call(i.ctx);return;case 1:while(++r<s)(i=t[r]).callback.call(i.ctx,n);return;case 2:while(++r<s)(i=t[r]).callback.call(i.ctx,n,a);return;case 3:while(++r<s)(i=t[r]).callback.call(i.ctx,n,a,o);return;default:while(++r<s)(i=t[r]).callback.apply(i.ctx,e);return}};var d={listenTo:\"on\",listenToOnce:\"once\"};i.each(d,function(t,e){u[e]=function(e,r,s){var n=this._listeningTo||(this._listeningTo={});var a=e._listenId||(e._listenId=i.uniqueId(\"l\"));n[a]=e;if(!s&&typeof r===\"object\")s=this;e[t](r,s,this);return this}});u.bind=u.on;u.unbind=u.off;i.extend(e,u);var p=e.Model=function(t,e){var r=t||{};e||(e={});this.cid=i.uniqueId(\"c\");this.attributes={};if(e.collection)this.collection=e.collection;if(e.parse)r=this.parse(r,e)||{};r=i.defaults({},r,i.result(this,\"defaults\"));this.set(r,e);this.changed={};this.initialize.apply(this,arguments)};i.extend(p.prototype,u,{changed:null,validationError:null,idAttribute:\"id\",initialize:function(){},toJSON:function(t){return i.clone(this.attributes)},sync:function(){return e.sync.apply(this,arguments)},get:function(t){return this.attributes[t]},escape:function(t){return i.escape(this.get(t))},has:function(t){return this.get(t)!=null},set:function(t,e,r){var s,n,a,o,h,u,l,c;if(t==null)return this;if(typeof t===\"object\"){n=t;r=e}else{(n={})[t]=e}r||(r={});if(!this._validate(n,r))return false;a=r.unset;h=r.silent;o=[];u=this._changing;this._changing=true;if(!u){this._previousAttributes=i.clone(this.attributes);this.changed={}}c=this.attributes,l=this._previousAttributes;if(this.idAttribute in n)this.id=n[this.idAttribute];for(s in n){e=n[s];if(!i.isEqual(c[s],e))o.push(s);if(!i.isEqual(l[s],e)){this.changed[s]=e}else{delete this.changed[s]}a?delete c[s]:c[s]=e}if(!h){if(o.length)this._pending=r;for(var f=0,d=o.length;f<d;f++){this.trigger(\"change:\"+o[f],this,c[o[f]],r)}}if(u)return this;if(!h){while(this._pending){r=this._pending;this._pending=false;this.trigger(\"change\",this,r)}}this._pending=false;this._changing=false;return this},unset:function(t,e){return this.set(t,void 0,i.extend({},e,{unset:true}))},clear:function(t){var e={};for(var r in this.attributes)e[r]=void 0;return this.set(e,i.extend({},t,{unset:true}))},hasChanged:function(t){if(t==null)return!i.isEmpty(this.changed);return i.has(this.changed,t)},changedAttributes:function(t){if(!t)return this.hasChanged()?i.clone(this.changed):false;var e,r=false;var s=this._changing?this._previousAttributes:this.attributes;for(var n in t){if(i.isEqual(s[n],e=t[n]))continue;(r||(r={}))[n]=e}return r},previous:function(t){if(t==null||!this._previousAttributes)return null;return this._previousAttributes[t]},previousAttributes:function(){return i.clone(this._previousAttributes)},fetch:function(t){t=t?i.clone(t):{};if(t.parse===void 0)t.parse=true;var e=this;var r=t.success;t.success=function(i){if(!e.set(e.parse(i,t),t))return false;if(r)r(e,i,t);e.trigger(\"sync\",e,i,t)};q(this,t);return this.sync(\"read\",this,t)},save:function(t,e,r){var s,n,a,o=this.attributes;if(t==null||typeof t===\"object\"){s=t;r=e}else{(s={})[t]=e}r=i.extend({validate:true},r);if(s&&!r.wait){if(!this.set(s,r))return false}else{if(!this._validate(s,r))return false}if(s&&r.wait){this.attributes=i.extend({},o,s)}if(r.parse===void 0)r.parse=true;var h=this;var u=r.success;r.success=function(t){h.attributes=o;var e=h.parse(t,r);if(r.wait)e=i.extend(s||{},e);if(i.isObject(e)&&!h.set(e,r)){return false}if(u)u(h,t,r);h.trigger(\"sync\",h,t,r)};q(this,r);n=this.isNew()?\"create\":r.patch?\"patch\":\"update\";if(n===\"patch\")r.attrs=s;a=this.sync(n,this,r);if(s&&r.wait)this.attributes=o;return a},destroy:function(t){t=t?i.clone(t):{};var e=this;var r=t.success;var s=function(){e.trigger(\"destroy\",e,e.collection,t)};t.success=function(i){if(t.wait||e.isNew())s();if(r)r(e,i,t);if(!e.isNew())e.trigger(\"sync\",e,i,t)};if(this.isNew()){t.success();return false}q(this,t);var n=this.sync(\"delete\",this,t);if(!t.wait)s();return n},url:function(){var t=i.result(this,\"urlRoot\")||i.result(this.collection,\"url\")||M();if(this.isNew())return t;return t.replace(/([^\\/])$/,\"$1/\")+encodeURIComponent(this.id)},parse:function(t,e){return t},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return!this.has(this.idAttribute)},isValid:function(t){return this._validate({},i.extend(t||{},{validate:true}))},_validate:function(t,e){if(!e.validate||!this.validate)return true;t=i.extend({},this.attributes,t);var r=this.validationError=this.validate(t,e)||null;if(!r)return true;this.trigger(\"invalid\",this,r,i.extend(e,{validationError:r}));return false}});var v=[\"keys\",\"values\",\"pairs\",\"invert\",\"pick\",\"omit\"];i.each(v,function(t){p.prototype[t]=function(){var e=o.call(arguments);e.unshift(this.attributes);return i[t].apply(i,e)}});var g=e.Collection=function(t,e){e||(e={});if(e.model)this.model=e.model;if(e.comparator!==void 0)this.comparator=e.comparator;this._reset();this.initialize.apply(this,arguments);if(t)this.reset(t,i.extend({silent:true},e))};var m={add:true,remove:true,merge:true};var y={add:true,remove:false};i.extend(g.prototype,u,{model:p,initialize:function(){},toJSON:function(t){return this.map(function(e){return e.toJSON(t)})},sync:function(){return e.sync.apply(this,arguments)},add:function(t,e){return this.set(t,i.extend({merge:false},e,y))},remove:function(t,e){var r=!i.isArray(t);t=r?[t]:i.clone(t);e||(e={});var s,n,a,o;for(s=0,n=t.length;s<n;s++){o=t[s]=this.get(t[s]);if(!o)continue;delete this._byId[o.id];delete this._byId[o.cid];a=this.indexOf(o);this.models.splice(a,1);this.length--;if(!e.silent){e.index=a;o.trigger(\"remove\",o,this,e)}this._removeReference(o,e)}return r?t[0]:t},set:function(t,e){e=i.defaults({},e,m);if(e.parse)t=this.parse(t,e);var r=!i.isArray(t);t=r?t?[t]:[]:i.clone(t);var s,n,a,o,h,u,l;var c=e.at;var f=this.model;var d=this.comparator&&c==null&&e.sort!==false;var v=i.isString(this.comparator)?this.comparator:null;var g=[],y=[],_={};var b=e.add,w=e.merge,x=e.remove;var E=!d&&b&&x?[]:false;for(s=0,n=t.length;s<n;s++){h=t[s]||{};if(h instanceof p){a=o=h}else{a=h[f.prototype.idAttribute||\"id\"]}if(u=this.get(a)){if(x)_[u.cid]=true;if(w){h=h===o?o.attributes:h;if(e.parse)h=u.parse(h,e);u.set(h,e);if(d&&!l&&u.hasChanged(v))l=true}t[s]=u}else if(b){o=t[s]=this._prepareModel(h,e);if(!o)continue;g.push(o);this._addReference(o,e)}o=u||o;if(E&&(o.isNew()||!_[o.id]))E.push(o);_[o.id]=true}if(x){for(s=0,n=this.length;s<n;++s){if(!_[(o=this.models[s]).cid])y.push(o)}if(y.length)this.remove(y,e)}if(g.length||E&&E.length){if(d)l=true;this.length+=g.length;if(c!=null){for(s=0,n=g.length;s<n;s++){this.models.splice(c+s,0,g[s])}}else{if(E)this.models.length=0;var k=E||g;for(s=0,n=k.length;s<n;s++){this.models.push(k[s])}}}if(l)this.sort({silent:true});if(!e.silent){for(s=0,n=g.length;s<n;s++){(o=g[s]).trigger(\"add\",o,this,e)}if(l||E&&E.length)this.trigger(\"sort\",this,e)}return r?t[0]:t},reset:function(t,e){e||(e={});for(var r=0,s=this.models.length;r<s;r++){this._removeReference(this.models[r],e)}e.previousModels=this.models;this._reset();t=this.add(t,i.extend({silent:true},e));if(!e.silent)this.trigger(\"reset\",this,e);return t},push:function(t,e){return this.add(t,i.extend({at:this.length},e))},pop:function(t){var e=this.at(this.length-1);this.remove(e,t);return e},unshift:function(t,e){return this.add(t,i.extend({at:0},e))},shift:function(t){var e=this.at(0);this.remove(e,t);return e},slice:function(){return o.apply(this.models,arguments)},get:function(t){if(t==null)return void 0;return this._byId[t]||this._byId[t.id]||this._byId[t.cid]},at:function(t){return this.models[t]},where:function(t,e){if(i.isEmpty(t))return e?void 0:[];return this[e?\"find\":\"filter\"](function(e){for(var i in t){if(t[i]!==e.get(i))return false}return true})},findWhere:function(t){return this.where(t,true)},sort:function(t){if(!this.comparator)throw new Error(\"Cannot sort a set without a comparator\");t||(t={});if(i.isString(this.comparator)||this.comparator.length===1){this.models=this.sortBy(this.comparator,this)}else{this.models.sort(i.bind(this.comparator,this))}if(!t.silent)this.trigger(\"sort\",this,t);return this},pluck:function(t){return i.invoke(this.models,\"get\",t)},fetch:function(t){t=t?i.clone(t):{};if(t.parse===void 0)t.parse=true;var e=t.success;var r=this;t.success=function(i){var s=t.reset?\"reset\":\"set\";r[s](i,t);if(e)e(r,i,t);r.trigger(\"sync\",r,i,t)};q(this,t);return this.sync(\"read\",this,t)},create:function(t,e){e=e?i.clone(e):{};if(!(t=this._prepareModel(t,e)))return false;if(!e.wait)this.add(t,e);var r=this;var s=e.success;e.success=function(t,i){if(e.wait)r.add(t,e);if(s)s(t,i,e)};t.save(null,e);return t},parse:function(t,e){return t},clone:function(){return new this.constructor(this.models)},_reset:function(){this.length=0;this.models=[];this._byId={}},_prepareModel:function(t,e){if(t instanceof p)return t;e=e?i.clone(e):{};e.collection=this;var r=new this.model(t,e);if(!r.validationError)return r;this.trigger(\"invalid\",this,r.validationError,e);return false},_addReference:function(t,e){this._byId[t.cid]=t;if(t.id!=null)this._byId[t.id]=t;if(!t.collection)t.collection=this;t.on(\"all\",this._onModelEvent,this)},_removeReference:function(t,e){if(this===t.collection)delete t.collection;t.off(\"all\",this._onModelEvent,this)},_onModelEvent:function(t,e,i,r){if((t===\"add\"||t===\"remove\")&&i!==this)return;if(t===\"destroy\")this.remove(e,r);if(e&&t===\"change:\"+e.idAttribute){delete this._byId[e.previous(e.idAttribute)];if(e.id!=null)this._byId[e.id]=e}this.trigger.apply(this,arguments)}});var _=[\"forEach\",\"each\",\"map\",\"collect\",\"reduce\",\"foldl\",\"inject\",\"reduceRight\",\"foldr\",\"find\",\"detect\",\"filter\",\"select\",\"reject\",\"every\",\"all\",\"some\",\"any\",\"include\",\"contains\",\"invoke\",\"max\",\"min\",\"toArray\",\"size\",\"first\",\"head\",\"take\",\"initial\",\"rest\",\"tail\",\"drop\",\"last\",\"without\",\"difference\",\"indexOf\",\"shuffle\",\"lastIndexOf\",\"isEmpty\",\"chain\",\"sample\"];i.each(_,function(t){g.prototype[t]=function(){var e=o.call(arguments);e.unshift(this.models);return i[t].apply(i,e)}});var b=[\"groupBy\",\"countBy\",\"sortBy\",\"indexBy\"];i.each(b,function(t){g.prototype[t]=function(e,r){var s=i.isFunction(e)?e:function(t){return t.get(e)};return i[t](this.models,s,r)}});var w=e.View=function(t){this.cid=i.uniqueId(\"view\");t||(t={});i.extend(this,i.pick(t,E));this._ensureElement();this.initialize.apply(this,arguments);this.delegateEvents()};var x=/^(\\S+)\\s*(.*)$/;var E=[\"model\",\"collection\",\"el\",\"id\",\"attributes\",\"className\",\"tagName\",\"events\"];i.extend(w.prototype,u,{tagName:\"div\",$:function(t){return this.$el.find(t)},initialize:function(){},render:function(){return this},remove:function(){this.$el.remove();this.stopListening();return this},setElement:function(t,i){if(this.$el)this.undelegateEvents();this.$el=t instanceof e.$?t:e.$(t);this.el=this.$el[0];if(i!==false)this.delegateEvents();return this},delegateEvents:function(t){if(!(t||(t=i.result(this,\"events\"))))return this;this.undelegateEvents();for(var e in t){var r=t[e];if(!i.isFunction(r))r=this[t[e]];if(!r)continue;var s=e.match(x);var n=s[1],a=s[2];r=i.bind(r,this);n+=\".delegateEvents\"+this.cid;if(a===\"\"){this.$el.on(n,r)}else{this.$el.on(n,a,r)}}return this},undelegateEvents:function(){this.$el.off(\".delegateEvents\"+this.cid);return this},_ensureElement:function(){if(!this.el){var t=i.extend({},i.result(this,\"attributes\"));if(this.id)t.id=i.result(this,\"id\");if(this.className)t[\"class\"]=i.result(this,\"className\");var r=e.$(\"<\"+i.result(this,\"tagName\")+\">\").attr(t);this.setElement(r,false)}else{this.setElement(i.result(this,\"el\"),false)}}});e.sync=function(t,r,s){var n=T[t];i.defaults(s||(s={}),{emulateHTTP:e.emulateHTTP,emulateJSON:e.emulateJSON});var a={type:n,dataType:\"json\"};if(!s.url){a.url=i.result(r,\"url\")||M()}if(s.data==null&&r&&(t===\"create\"||t===\"update\"||t===\"patch\")){a.contentType=\"application/json\";a.data=JSON.stringify(s.attrs||r.toJSON(s))}if(s.emulateJSON){a.contentType=\"application/x-www-form-urlencoded\";a.data=a.data?{model:a.data}:{}}if(s.emulateHTTP&&(n===\"PUT\"||n===\"DELETE\"||n===\"PATCH\")){a.type=\"POST\";if(s.emulateJSON)a.data._method=n;var o=s.beforeSend;s.beforeSend=function(t){t.setRequestHeader(\"X-HTTP-Method-Override\",n);if(o)return o.apply(this,arguments)}}if(a.type!==\"GET\"&&!s.emulateJSON){a.processData=false}if(a.type===\"PATCH\"&&k){a.xhr=function(){return new ActiveXObject(\"Microsoft.XMLHTTP\")}}var h=s.xhr=e.ajax(i.extend(a,s));r.trigger(\"request\",r,h,s);return h};var k=typeof window!==\"undefined\"&&!!window.ActiveXObject&&!(window.XMLHttpRequest&&(new XMLHttpRequest).dispatchEvent);var T={create:\"POST\",update:\"PUT\",patch:\"PATCH\",\"delete\":\"DELETE\",read:\"GET\"};e.ajax=function(){return e.$.ajax.apply(e.$,arguments)};var $=e.Router=function(t){t||(t={});if(t.routes)this.routes=t.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var S=/\\((.*?)\\)/g;var H=/(\\(\\?)?:\\w+/g;var A=/\\*\\w+/g;var I=/[\\-{}\\[\\]+?.,\\\\\\^$|#\\s]/g;i.extend($.prototype,u,{initialize:function(){},route:function(t,r,s){if(!i.isRegExp(t))t=this._routeToRegExp(t);if(i.isFunction(r)){s=r;r=\"\"}if(!s)s=this[r];var n=this;e.history.route(t,function(i){var a=n._extractParameters(t,i);n.execute(s,a);n.trigger.apply(n,[\"route:\"+r].concat(a));n.trigger(\"route\",r,a);e.history.trigger(\"route\",n,r,a)});return this},execute:function(t,e){if(t)t.apply(this,e)},navigate:function(t,i){e.history.navigate(t,i);return this},_bindRoutes:function(){if(!this.routes)return;this.routes=i.result(this,\"routes\");var t,e=i.keys(this.routes);while((t=e.pop())!=null){this.route(t,this.routes[t])}},_routeToRegExp:function(t){t=t.replace(I,\"\\\\$&\").replace(S,\"(?:$1)?\").replace(H,function(t,e){return e?t:\"([^/?]+)\"}).replace(A,\"([^?]*?)\");return new RegExp(\"^\"+t+\"(?:\\\\?([\\\\s\\\\S]*))?$\")},_extractParameters:function(t,e){var r=t.exec(e).slice(1);return i.map(r,function(t,e){if(e===r.length-1)return t||null;return t?decodeURIComponent(t):null})}});var N=e.History=function(){this.handlers=[];i.bindAll(this,\"checkUrl\");if(typeof window!==\"undefined\"){this.location=window.location;this.history=window.history}};var R=/^[#\\/]|\\s+$/g;var O=/^\\/+|\\/+$/g;var P=/msie [\\w.]+/;var C=/\\/$/;var j=/#.*$/;N.started=false;i.extend(N.prototype,u,{interval:50,atRoot:function(){return this.location.pathname.replace(/[^\\/]$/,\"$&/\")===this.root},getHash:function(t){var e=(t||this).location.href.match(/#(.*)$/);return e?e[1]:\"\"},getFragment:function(t,e){if(t==null){if(this._hasPushState||!this._wantsHashChange||e){t=decodeURI(this.location.pathname+this.location.search);var i=this.root.replace(C,\"\");if(!t.indexOf(i))t=t.slice(i.length)}else{t=this.getHash()}}return t.replace(R,\"\")},start:function(t){if(N.started)throw new Error(\"Backbone.history has already been started\");N.started=true;this.options=i.extend({root:\"/\"},this.options,t);this.root=this.options.root;this._wantsHashChange=this.options.hashChange!==false;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.options.pushState&&this.history&&this.history.pushState);var r=this.getFragment();var s=document.documentMode;var n=P.exec(navigator.userAgent.toLowerCase())&&(!s||s<=7);this.root=(\"/\"+this.root+\"/\").replace(O,\"/\");if(n&&this._wantsHashChange){var a=e.$('<iframe src=\"javascript:0\" tabindex=\"-1\">');this.iframe=a.hide().appendTo(\"body\")[0].contentWindow;this.navigate(r)}if(this._hasPushState){e.$(window).on(\"popstate\",this.checkUrl)}else if(this._wantsHashChange&&\"onhashchange\"in window&&!n){e.$(window).on(\"hashchange\",this.checkUrl)}else if(this._wantsHashChange){this._checkUrlInterval=setInterval(this.checkUrl,this.interval)}this.fragment=r;var o=this.location;if(this._wantsHashChange&&this._wantsPushState){if(!this._hasPushState&&!this.atRoot()){this.fragment=this.getFragment(null,true);this.location.replace(this.root+\"#\"+this.fragment);return true}else if(this._hasPushState&&this.atRoot()&&o.hash){this.fragment=this.getHash().replace(R,\"\");this.history.replaceState({},document.title,this.root+this.fragment)}}if(!this.options.silent)return this.loadUrl()},stop:function(){e.$(window).off(\"popstate\",this.checkUrl).off(\"hashchange\",this.checkUrl);if(this._checkUrlInterval)clearInterval(this._checkUrlInterval);N.started=false},route:function(t,e){this.handlers.unshift({route:t,callback:e})},checkUrl:function(t){var e=this.getFragment();if(e===this.fragment&&this.iframe){e=this.getFragment(this.getHash(this.iframe))}if(e===this.fragment)return false;if(this.iframe)this.navigate(e);this.loadUrl()},loadUrl:function(t){t=this.fragment=this.getFragment(t);return i.any(this.handlers,function(e){if(e.route.test(t)){e.callback(t);return true}})},navigate:function(t,e){if(!N.started)return false;if(!e||e===true)e={trigger:!!e};var i=this.root+(t=this.getFragment(t||\"\"));t=t.replace(j,\"\");if(this.fragment===t)return;this.fragment=t;if(t===\"\"&&i!==\"/\")i=i.slice(0,-1);if(this._hasPushState){this.history[e.replace?\"replaceState\":\"pushState\"]({},document.title,i)}else if(this._wantsHashChange){this._updateHash(this.location,t,e.replace);if(this.iframe&&t!==this.getFragment(this.getHash(this.iframe))){if(!e.replace)this.iframe.document.open().close();this._updateHash(this.iframe.location,t,e.replace)}}else{return this.location.assign(i)}if(e.trigger)return this.loadUrl(t)},_updateHash:function(t,e,i){if(i){var r=t.href.replace(/(javascript:|#).*$/,\"\");t.replace(r+\"#\"+e)}else{t.hash=\"#\"+e}}});e.history=new N;var U=function(t,e){var r=this;var s;if(t&&i.has(t,\"constructor\")){s=t.constructor}else{s=function(){return r.apply(this,arguments)}}i.extend(s,r,e);var n=function(){this.constructor=s};n.prototype=r.prototype;s.prototype=new n;if(t)i.extend(s.prototype,t);s.__super__=r.prototype;return s};p.extend=g.extend=$.extend=w.extend=N.extend=U;var M=function(){throw new Error('A \"url\" property or function must be specified')};var q=function(t,e){var i=e.error;e.error=function(r){if(i)i(t,r,e);t.trigger(\"error\",t,r,e)}};return e});\n//# sourceMappingURL=backbone-min.map"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/affix.js",
    "content": "/* ========================================================================\n * Bootstrap: affix.js v3.3.1\n * http://getbootstrap.com/javascript/#affix\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // AFFIX CLASS DEFINITION\n  // ======================\n\n  var Affix = function (element, options) {\n    this.options = $.extend({}, Affix.DEFAULTS, options)\n\n    this.$target = $(this.options.target)\n      .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))\n      .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))\n\n    this.$element     = $(element)\n    this.affixed      =\n    this.unpin        =\n    this.pinnedOffset = null\n\n    this.checkPosition()\n  }\n\n  Affix.VERSION  = '3.3.1'\n\n  Affix.RESET    = 'affix affix-top affix-bottom'\n\n  Affix.DEFAULTS = {\n    offset: 0,\n    target: window\n  }\n\n  Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {\n    var scrollTop    = this.$target.scrollTop()\n    var position     = this.$element.offset()\n    var targetHeight = this.$target.height()\n\n    if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false\n\n    if (this.affixed == 'bottom') {\n      if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'\n      return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'\n    }\n\n    var initializing   = this.affixed == null\n    var colliderTop    = initializing ? scrollTop : position.top\n    var colliderHeight = initializing ? targetHeight : height\n\n    if (offsetTop != null && colliderTop <= offsetTop) return 'top'\n    if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'\n\n    return false\n  }\n\n  Affix.prototype.getPinnedOffset = function () {\n    if (this.pinnedOffset) return this.pinnedOffset\n    this.$element.removeClass(Affix.RESET).addClass('affix')\n    var scrollTop = this.$target.scrollTop()\n    var position  = this.$element.offset()\n    return (this.pinnedOffset = position.top - scrollTop)\n  }\n\n  Affix.prototype.checkPositionWithEventLoop = function () {\n    setTimeout($.proxy(this.checkPosition, this), 1)\n  }\n\n  Affix.prototype.checkPosition = function () {\n    if (!this.$element.is(':visible')) return\n\n    var height       = this.$element.height()\n    var offset       = this.options.offset\n    var offsetTop    = offset.top\n    var offsetBottom = offset.bottom\n    var scrollHeight = $('body').height()\n\n    if (typeof offset != 'object')         offsetBottom = offsetTop = offset\n    if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)\n    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)\n\n    var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)\n\n    if (this.affixed != affix) {\n      if (this.unpin != null) this.$element.css('top', '')\n\n      var affixType = 'affix' + (affix ? '-' + affix : '')\n      var e         = $.Event(affixType + '.bs.affix')\n\n      this.$element.trigger(e)\n\n      if (e.isDefaultPrevented()) return\n\n      this.affixed = affix\n      this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null\n\n      this.$element\n        .removeClass(Affix.RESET)\n        .addClass(affixType)\n        .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')\n    }\n\n    if (affix == 'bottom') {\n      this.$element.offset({\n        top: scrollHeight - height - offsetBottom\n      })\n    }\n  }\n\n\n  // AFFIX PLUGIN DEFINITION\n  // =======================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.affix')\n      var options = typeof option == 'object' && option\n\n      if (!data) $this.data('bs.affix', (data = new Affix(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.affix\n\n  $.fn.affix             = Plugin\n  $.fn.affix.Constructor = Affix\n\n\n  // AFFIX NO CONFLICT\n  // =================\n\n  $.fn.affix.noConflict = function () {\n    $.fn.affix = old\n    return this\n  }\n\n\n  // AFFIX DATA-API\n  // ==============\n\n  $(window).on('load', function () {\n    $('[data-spy=\"affix\"]').each(function () {\n      var $spy = $(this)\n      var data = $spy.data()\n\n      data.offset = data.offset || {}\n\n      if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom\n      if (data.offsetTop    != null) data.offset.top    = data.offsetTop\n\n      Plugin.call($spy, data)\n    })\n  })\n\n}(jQuery);\n"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/alert.js",
    "content": "/* ========================================================================\n * Bootstrap: alert.js v3.3.1\n * http://getbootstrap.com/javascript/#alerts\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // ALERT CLASS DEFINITION\n  // ======================\n\n  var dismiss = '[data-dismiss=\"alert\"]'\n  var Alert   = function (el) {\n    $(el).on('click', dismiss, this.close)\n  }\n\n  Alert.VERSION = '3.3.1'\n\n  Alert.TRANSITION_DURATION = 150\n\n  Alert.prototype.close = function (e) {\n    var $this    = $(this)\n    var selector = $this.attr('data-target')\n\n    if (!selector) {\n      selector = $this.attr('href')\n      selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, '') // strip for ie7\n    }\n\n    var $parent = $(selector)\n\n    if (e) e.preventDefault()\n\n    if (!$parent.length) {\n      $parent = $this.closest('.alert')\n    }\n\n    $parent.trigger(e = $.Event('close.bs.alert'))\n\n    if (e.isDefaultPrevented()) return\n\n    $parent.removeClass('in')\n\n    function removeElement() {\n      // detach from parent, fire event then clean up data\n      $parent.detach().trigger('closed.bs.alert').remove()\n    }\n\n    $.support.transition && $parent.hasClass('fade') ?\n      $parent\n        .one('bsTransitionEnd', removeElement)\n        .emulateTransitionEnd(Alert.TRANSITION_DURATION) :\n      removeElement()\n  }\n\n\n  // ALERT PLUGIN DEFINITION\n  // =======================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this = $(this)\n      var data  = $this.data('bs.alert')\n\n      if (!data) $this.data('bs.alert', (data = new Alert(this)))\n      if (typeof option == 'string') data[option].call($this)\n    })\n  }\n\n  var old = $.fn.alert\n\n  $.fn.alert             = Plugin\n  $.fn.alert.Constructor = Alert\n\n\n  // ALERT NO CONFLICT\n  // =================\n\n  $.fn.alert.noConflict = function () {\n    $.fn.alert = old\n    return this\n  }\n\n\n  // ALERT DATA-API\n  // ==============\n\n  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)\n\n}(jQuery);\n"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/button.js",
    "content": "/* ========================================================================\n * Bootstrap: button.js v3.3.1\n * http://getbootstrap.com/javascript/#buttons\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // BUTTON PUBLIC CLASS DEFINITION\n  // ==============================\n\n  var Button = function (element, options) {\n    this.$element  = $(element)\n    this.options   = $.extend({}, Button.DEFAULTS, options)\n    this.isLoading = false\n  }\n\n  Button.VERSION  = '3.3.1'\n\n  Button.DEFAULTS = {\n    loadingText: 'loading...'\n  }\n\n  Button.prototype.setState = function (state) {\n    var d    = 'disabled'\n    var $el  = this.$element\n    var val  = $el.is('input') ? 'val' : 'html'\n    var data = $el.data()\n\n    state = state + 'Text'\n\n    if (data.resetText == null) $el.data('resetText', $el[val]())\n\n    // push to event loop to allow forms to submit\n    setTimeout($.proxy(function () {\n      $el[val](data[state] == null ? this.options[state] : data[state])\n\n      if (state == 'loadingText') {\n        this.isLoading = true\n        $el.addClass(d).attr(d, d)\n      } else if (this.isLoading) {\n        this.isLoading = false\n        $el.removeClass(d).removeAttr(d)\n      }\n    }, this), 0)\n  }\n\n  Button.prototype.toggle = function () {\n    var changed = true\n    var $parent = this.$element.closest('[data-toggle=\"buttons\"]')\n\n    if ($parent.length) {\n      var $input = this.$element.find('input')\n      if ($input.prop('type') == 'radio') {\n        if ($input.prop('checked') && this.$element.hasClass('active')) changed = false\n        else $parent.find('.active').removeClass('active')\n      }\n      if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change')\n    } else {\n      this.$element.attr('aria-pressed', !this.$element.hasClass('active'))\n    }\n\n    if (changed) this.$element.toggleClass('active')\n  }\n\n\n  // BUTTON PLUGIN DEFINITION\n  // ========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.button')\n      var options = typeof option == 'object' && option\n\n      if (!data) $this.data('bs.button', (data = new Button(this, options)))\n\n      if (option == 'toggle') data.toggle()\n      else if (option) data.setState(option)\n    })\n  }\n\n  var old = $.fn.button\n\n  $.fn.button             = Plugin\n  $.fn.button.Constructor = Button\n\n\n  // BUTTON NO CONFLICT\n  // ==================\n\n  $.fn.button.noConflict = function () {\n    $.fn.button = old\n    return this\n  }\n\n\n  // BUTTON DATA-API\n  // ===============\n\n  $(document)\n    .on('click.bs.button.data-api', '[data-toggle^=\"button\"]', function (e) {\n      var $btn = $(e.target)\n      if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')\n      Plugin.call($btn, 'toggle')\n      e.preventDefault()\n    })\n    .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^=\"button\"]', function (e) {\n      $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))\n    })\n\n}(jQuery);\n"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/carousel.js",
    "content": "/* ========================================================================\n * Bootstrap: carousel.js v3.3.1\n * http://getbootstrap.com/javascript/#carousel\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // CAROUSEL CLASS DEFINITION\n  // =========================\n\n  var Carousel = function (element, options) {\n    this.$element    = $(element)\n    this.$indicators = this.$element.find('.carousel-indicators')\n    this.options     = options\n    this.paused      =\n    this.sliding     =\n    this.interval    =\n    this.$active     =\n    this.$items      = null\n\n    this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))\n\n    this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element\n      .on('mouseenter.bs.carousel', $.proxy(this.pause, this))\n      .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))\n  }\n\n  Carousel.VERSION  = '3.3.1'\n\n  Carousel.TRANSITION_DURATION = 600\n\n  Carousel.DEFAULTS = {\n    interval: 5000,\n    pause: 'hover',\n    wrap: true,\n    keyboard: true\n  }\n\n  Carousel.prototype.keydown = function (e) {\n    if (/input|textarea/i.test(e.target.tagName)) return\n    switch (e.which) {\n      case 37: this.prev(); break\n      case 39: this.next(); break\n      default: return\n    }\n\n    e.preventDefault()\n  }\n\n  Carousel.prototype.cycle = function (e) {\n    e || (this.paused = false)\n\n    this.interval && clearInterval(this.interval)\n\n    this.options.interval\n      && !this.paused\n      && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))\n\n    return this\n  }\n\n  Carousel.prototype.getItemIndex = function (item) {\n    this.$items = item.parent().children('.item')\n    return this.$items.index(item || this.$active)\n  }\n\n  Carousel.prototype.getItemForDirection = function (direction, active) {\n    var delta = direction == 'prev' ? -1 : 1\n    var activeIndex = this.getItemIndex(active)\n    var itemIndex = (activeIndex + delta) % this.$items.length\n    return this.$items.eq(itemIndex)\n  }\n\n  Carousel.prototype.to = function (pos) {\n    var that        = this\n    var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))\n\n    if (pos > (this.$items.length - 1) || pos < 0) return\n\n    if (this.sliding)       return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, \"slid\"\n    if (activeIndex == pos) return this.pause().cycle()\n\n    return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))\n  }\n\n  Carousel.prototype.pause = function (e) {\n    e || (this.paused = true)\n\n    if (this.$element.find('.next, .prev').length && $.support.transition) {\n      this.$element.trigger($.support.transition.end)\n      this.cycle(true)\n    }\n\n    this.interval = clearInterval(this.interval)\n\n    return this\n  }\n\n  Carousel.prototype.next = function () {\n    if (this.sliding) return\n    return this.slide('next')\n  }\n\n  Carousel.prototype.prev = function () {\n    if (this.sliding) return\n    return this.slide('prev')\n  }\n\n  Carousel.prototype.slide = function (type, next) {\n    var $active   = this.$element.find('.item.active')\n    var $next     = next || this.getItemForDirection(type, $active)\n    var isCycling = this.interval\n    var direction = type == 'next' ? 'left' : 'right'\n    var fallback  = type == 'next' ? 'first' : 'last'\n    var that      = this\n\n    if (!$next.length) {\n      if (!this.options.wrap) return\n      $next = this.$element.find('.item')[fallback]()\n    }\n\n    if ($next.hasClass('active')) return (this.sliding = false)\n\n    var relatedTarget = $next[0]\n    var slideEvent = $.Event('slide.bs.carousel', {\n      relatedTarget: relatedTarget,\n      direction: direction\n    })\n    this.$element.trigger(slideEvent)\n    if (slideEvent.isDefaultPrevented()) return\n\n    this.sliding = true\n\n    isCycling && this.pause()\n\n    if (this.$indicators.length) {\n      this.$indicators.find('.active').removeClass('active')\n      var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])\n      $nextIndicator && $nextIndicator.addClass('active')\n    }\n\n    var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, \"slid\"\n    if ($.support.transition && this.$element.hasClass('slide')) {\n      $next.addClass(type)\n      $next[0].offsetWidth // force reflow\n      $active.addClass(direction)\n      $next.addClass(direction)\n      $active\n        .one('bsTransitionEnd', function () {\n          $next.removeClass([type, direction].join(' ')).addClass('active')\n          $active.removeClass(['active', direction].join(' '))\n          that.sliding = false\n          setTimeout(function () {\n            that.$element.trigger(slidEvent)\n          }, 0)\n        })\n        .emulateTransitionEnd(Carousel.TRANSITION_DURATION)\n    } else {\n      $active.removeClass('active')\n      $next.addClass('active')\n      this.sliding = false\n      this.$element.trigger(slidEvent)\n    }\n\n    isCycling && this.cycle()\n\n    return this\n  }\n\n\n  // CAROUSEL PLUGIN DEFINITION\n  // ==========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.carousel')\n      var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)\n      var action  = typeof option == 'string' ? option : options.slide\n\n      if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))\n      if (typeof option == 'number') data.to(option)\n      else if (action) data[action]()\n      else if (options.interval) data.pause().cycle()\n    })\n  }\n\n  var old = $.fn.carousel\n\n  $.fn.carousel             = Plugin\n  $.fn.carousel.Constructor = Carousel\n\n\n  // CAROUSEL NO CONFLICT\n  // ====================\n\n  $.fn.carousel.noConflict = function () {\n    $.fn.carousel = old\n    return this\n  }\n\n\n  // CAROUSEL DATA-API\n  // =================\n\n  var clickHandler = function (e) {\n    var href\n    var $this   = $(this)\n    var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '')) // strip for ie7\n    if (!$target.hasClass('carousel')) return\n    var options = $.extend({}, $target.data(), $this.data())\n    var slideIndex = $this.attr('data-slide-to')\n    if (slideIndex) options.interval = false\n\n    Plugin.call($target, options)\n\n    if (slideIndex) {\n      $target.data('bs.carousel').to(slideIndex)\n    }\n\n    e.preventDefault()\n  }\n\n  $(document)\n    .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)\n    .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)\n\n  $(window).on('load', function () {\n    $('[data-ride=\"carousel\"]').each(function () {\n      var $carousel = $(this)\n      Plugin.call($carousel, $carousel.data())\n    })\n  })\n\n}(jQuery);\n"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/collapse.js",
    "content": "/* ========================================================================\n * Bootstrap: collapse.js v3.3.1\n * http://getbootstrap.com/javascript/#collapse\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // COLLAPSE PUBLIC CLASS DEFINITION\n  // ================================\n\n  var Collapse = function (element, options) {\n    this.$element      = $(element)\n    this.options       = $.extend({}, Collapse.DEFAULTS, options)\n    this.$trigger      = $(this.options.trigger).filter('[href=\"#' + element.id + '\"], [data-target=\"#' + element.id + '\"]')\n    this.transitioning = null\n\n    if (this.options.parent) {\n      this.$parent = this.getParent()\n    } else {\n      this.addAriaAndCollapsedClass(this.$element, this.$trigger)\n    }\n\n    if (this.options.toggle) this.toggle()\n  }\n\n  Collapse.VERSION  = '3.3.1'\n\n  Collapse.TRANSITION_DURATION = 350\n\n  Collapse.DEFAULTS = {\n    toggle: true,\n    trigger: '[data-toggle=\"collapse\"]'\n  }\n\n  Collapse.prototype.dimension = function () {\n    var hasWidth = this.$element.hasClass('width')\n    return hasWidth ? 'width' : 'height'\n  }\n\n  Collapse.prototype.show = function () {\n    if (this.transitioning || this.$element.hasClass('in')) return\n\n    var activesData\n    var actives = this.$parent && this.$parent.find('> .panel').children('.in, .collapsing')\n\n    if (actives && actives.length) {\n      activesData = actives.data('bs.collapse')\n      if (activesData && activesData.transitioning) return\n    }\n\n    var startEvent = $.Event('show.bs.collapse')\n    this.$element.trigger(startEvent)\n    if (startEvent.isDefaultPrevented()) return\n\n    if (actives && actives.length) {\n      Plugin.call(actives, 'hide')\n      activesData || actives.data('bs.collapse', null)\n    }\n\n    var dimension = this.dimension()\n\n    this.$element\n      .removeClass('collapse')\n      .addClass('collapsing')[dimension](0)\n      .attr('aria-expanded', true)\n\n    this.$trigger\n      .removeClass('collapsed')\n      .attr('aria-expanded', true)\n\n    this.transitioning = 1\n\n    var complete = function () {\n      this.$element\n        .removeClass('collapsing')\n        .addClass('collapse in')[dimension]('')\n      this.transitioning = 0\n      this.$element\n        .trigger('shown.bs.collapse')\n    }\n\n    if (!$.support.transition) return complete.call(this)\n\n    var scrollSize = $.camelCase(['scroll', dimension].join('-'))\n\n    this.$element\n      .one('bsTransitionEnd', $.proxy(complete, this))\n      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])\n  }\n\n  Collapse.prototype.hide = function () {\n    if (this.transitioning || !this.$element.hasClass('in')) return\n\n    var startEvent = $.Event('hide.bs.collapse')\n    this.$element.trigger(startEvent)\n    if (startEvent.isDefaultPrevented()) return\n\n    var dimension = this.dimension()\n\n    this.$element[dimension](this.$element[dimension]())[0].offsetHeight\n\n    this.$element\n      .addClass('collapsing')\n      .removeClass('collapse in')\n      .attr('aria-expanded', false)\n\n    this.$trigger\n      .addClass('collapsed')\n      .attr('aria-expanded', false)\n\n    this.transitioning = 1\n\n    var complete = function () {\n      this.transitioning = 0\n      this.$element\n        .removeClass('collapsing')\n        .addClass('collapse')\n        .trigger('hidden.bs.collapse')\n    }\n\n    if (!$.support.transition) return complete.call(this)\n\n    this.$element\n      [dimension](0)\n      .one('bsTransitionEnd', $.proxy(complete, this))\n      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)\n  }\n\n  Collapse.prototype.toggle = function () {\n    this[this.$element.hasClass('in') ? 'hide' : 'show']()\n  }\n\n  Collapse.prototype.getParent = function () {\n    return $(this.options.parent)\n      .find('[data-toggle=\"collapse\"][data-parent=\"' + this.options.parent + '\"]')\n      .each($.proxy(function (i, element) {\n        var $element = $(element)\n        this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)\n      }, this))\n      .end()\n  }\n\n  Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {\n    var isOpen = $element.hasClass('in')\n\n    $element.attr('aria-expanded', isOpen)\n    $trigger\n      .toggleClass('collapsed', !isOpen)\n      .attr('aria-expanded', isOpen)\n  }\n\n  function getTargetFromTrigger($trigger) {\n    var href\n    var target = $trigger.attr('data-target')\n      || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '') // strip for ie7\n\n    return $(target)\n  }\n\n\n  // COLLAPSE PLUGIN DEFINITION\n  // ==========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.collapse')\n      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)\n\n      if (!data && options.toggle && option == 'show') options.toggle = false\n      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.collapse\n\n  $.fn.collapse             = Plugin\n  $.fn.collapse.Constructor = Collapse\n\n\n  // COLLAPSE NO CONFLICT\n  // ====================\n\n  $.fn.collapse.noConflict = function () {\n    $.fn.collapse = old\n    return this\n  }\n\n\n  // COLLAPSE DATA-API\n  // =================\n\n  $(document).on('click.bs.collapse.data-api', '[data-toggle=\"collapse\"]', function (e) {\n    var $this   = $(this)\n\n    if (!$this.attr('data-target')) e.preventDefault()\n\n    var $target = getTargetFromTrigger($this)\n    var data    = $target.data('bs.collapse')\n    var option  = data ? 'toggle' : $.extend({}, $this.data(), { trigger: this })\n\n    Plugin.call($target, option)\n  })\n\n}(jQuery);\n"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/dropdown.js",
    "content": "/* ========================================================================\n * Bootstrap: dropdown.js v3.3.1\n * http://getbootstrap.com/javascript/#dropdowns\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // DROPDOWN CLASS DEFINITION\n  // =========================\n\n  var backdrop = '.dropdown-backdrop'\n  var toggle   = '[data-toggle=\"dropdown\"]'\n  var Dropdown = function (element) {\n    $(element).on('click.bs.dropdown', this.toggle)\n  }\n\n  Dropdown.VERSION = '3.3.1'\n\n  Dropdown.prototype.toggle = function (e) {\n    var $this = $(this)\n\n    if ($this.is('.disabled, :disabled')) return\n\n    var $parent  = getParent($this)\n    var isActive = $parent.hasClass('open')\n\n    clearMenus()\n\n    if (!isActive) {\n      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {\n        // if mobile we use a backdrop because click events don't delegate\n        $('<div class=\"dropdown-backdrop\"/>').insertAfter($(this)).on('click', clearMenus)\n      }\n\n      var relatedTarget = { relatedTarget: this }\n      $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))\n\n      if (e.isDefaultPrevented()) return\n\n      $this\n        .trigger('focus')\n        .attr('aria-expanded', 'true')\n\n      $parent\n        .toggleClass('open')\n        .trigger('shown.bs.dropdown', relatedTarget)\n    }\n\n    return false\n  }\n\n  Dropdown.prototype.keydown = function (e) {\n    if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return\n\n    var $this = $(this)\n\n    e.preventDefault()\n    e.stopPropagation()\n\n    if ($this.is('.disabled, :disabled')) return\n\n    var $parent  = getParent($this)\n    var isActive = $parent.hasClass('open')\n\n    if ((!isActive && e.which != 27) || (isActive && e.which == 27)) {\n      if (e.which == 27) $parent.find(toggle).trigger('focus')\n      return $this.trigger('click')\n    }\n\n    var desc = ' li:not(.divider):visible a'\n    var $items = $parent.find('[role=\"menu\"]' + desc + ', [role=\"listbox\"]' + desc)\n\n    if (!$items.length) return\n\n    var index = $items.index(e.target)\n\n    if (e.which == 38 && index > 0)                 index--                        // up\n    if (e.which == 40 && index < $items.length - 1) index++                        // down\n    if (!~index)                                      index = 0\n\n    $items.eq(index).trigger('focus')\n  }\n\n  function clearMenus(e) {\n    if (e && e.which === 3) return\n    $(backdrop).remove()\n    $(toggle).each(function () {\n      var $this         = $(this)\n      var $parent       = getParent($this)\n      var relatedTarget = { relatedTarget: this }\n\n      if (!$parent.hasClass('open')) return\n\n      $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))\n\n      if (e.isDefaultPrevented()) return\n\n      $this.attr('aria-expanded', 'false')\n      $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)\n    })\n  }\n\n  function getParent($this) {\n    var selector = $this.attr('data-target')\n\n    if (!selector) {\n      selector = $this.attr('href')\n      selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\\s]*$)/, '') // strip for ie7\n    }\n\n    var $parent = selector && $(selector)\n\n    return $parent && $parent.length ? $parent : $this.parent()\n  }\n\n\n  // DROPDOWN PLUGIN DEFINITION\n  // ==========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this = $(this)\n      var data  = $this.data('bs.dropdown')\n\n      if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))\n      if (typeof option == 'string') data[option].call($this)\n    })\n  }\n\n  var old = $.fn.dropdown\n\n  $.fn.dropdown             = Plugin\n  $.fn.dropdown.Constructor = Dropdown\n\n\n  // DROPDOWN NO CONFLICT\n  // ====================\n\n  $.fn.dropdown.noConflict = function () {\n    $.fn.dropdown = old\n    return this\n  }\n\n\n  // APPLY TO STANDARD DROPDOWN ELEMENTS\n  // ===================================\n\n  $(document)\n    .on('click.bs.dropdown.data-api', clearMenus)\n    .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })\n    .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)\n    .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)\n    .on('keydown.bs.dropdown.data-api', '[role=\"menu\"]', Dropdown.prototype.keydown)\n    .on('keydown.bs.dropdown.data-api', '[role=\"listbox\"]', Dropdown.prototype.keydown)\n\n}(jQuery);\n"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/modal.js",
    "content": "/* ========================================================================\n * Bootstrap: modal.js v3.3.1\n * http://getbootstrap.com/javascript/#modals\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // MODAL CLASS DEFINITION\n  // ======================\n\n  var Modal = function (element, options) {\n    this.options        = options\n    this.$body          = $(document.body)\n    this.$element       = $(element)\n    this.$backdrop      =\n    this.isShown        = null\n    this.scrollbarWidth = 0\n\n    if (this.options.remote) {\n      this.$element\n        .find('.modal-content')\n        .load(this.options.remote, $.proxy(function () {\n          this.$element.trigger('loaded.bs.modal')\n        }, this))\n    }\n  }\n\n  Modal.VERSION  = '3.3.1'\n\n  Modal.TRANSITION_DURATION = 300\n  Modal.BACKDROP_TRANSITION_DURATION = 150\n\n  Modal.DEFAULTS = {\n    backdrop: true,\n    keyboard: true,\n    show: true\n  }\n\n  Modal.prototype.toggle = function (_relatedTarget) {\n    return this.isShown ? this.hide() : this.show(_relatedTarget)\n  }\n\n  Modal.prototype.show = function (_relatedTarget) {\n    var that = this\n    var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })\n\n    this.$element.trigger(e)\n\n    if (this.isShown || e.isDefaultPrevented()) return\n\n    this.isShown = true\n\n    this.checkScrollbar()\n    this.setScrollbar()\n    this.$body.addClass('modal-open')\n\n    this.escape()\n    this.resize()\n\n    this.$element.on('click.dismiss.bs.modal', '[data-dismiss=\"modal\"]', $.proxy(this.hide, this))\n\n    this.backdrop(function () {\n      var transition = $.support.transition && that.$element.hasClass('fade')\n\n      if (!that.$element.parent().length) {\n        that.$element.appendTo(that.$body) // don't move modals dom position\n      }\n\n      that.$element\n        .show()\n        .scrollTop(0)\n\n      if (that.options.backdrop) that.adjustBackdrop()\n      that.adjustDialog()\n\n      if (transition) {\n        that.$element[0].offsetWidth // force reflow\n      }\n\n      that.$element\n        .addClass('in')\n        .attr('aria-hidden', false)\n\n      that.enforceFocus()\n\n      var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })\n\n      transition ?\n        that.$element.find('.modal-dialog') // wait for modal to slide in\n          .one('bsTransitionEnd', function () {\n            that.$element.trigger('focus').trigger(e)\n          })\n          .emulateTransitionEnd(Modal.TRANSITION_DURATION) :\n        that.$element.trigger('focus').trigger(e)\n    })\n  }\n\n  Modal.prototype.hide = function (e) {\n    if (e) e.preventDefault()\n\n    e = $.Event('hide.bs.modal')\n\n    this.$element.trigger(e)\n\n    if (!this.isShown || e.isDefaultPrevented()) return\n\n    this.isShown = false\n\n    this.escape()\n    this.resize()\n\n    $(document).off('focusin.bs.modal')\n\n    this.$element\n      .removeClass('in')\n      .attr('aria-hidden', true)\n      .off('click.dismiss.bs.modal')\n\n    $.support.transition && this.$element.hasClass('fade') ?\n      this.$element\n        .one('bsTransitionEnd', $.proxy(this.hideModal, this))\n        .emulateTransitionEnd(Modal.TRANSITION_DURATION) :\n      this.hideModal()\n  }\n\n  Modal.prototype.enforceFocus = function () {\n    $(document)\n      .off('focusin.bs.modal') // guard against infinite focus loop\n      .on('focusin.bs.modal', $.proxy(function (e) {\n        if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {\n          this.$element.trigger('focus')\n        }\n      }, this))\n  }\n\n  Modal.prototype.escape = function () {\n    if (this.isShown && this.options.keyboard) {\n      this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {\n        e.which == 27 && this.hide()\n      }, this))\n    } else if (!this.isShown) {\n      this.$element.off('keydown.dismiss.bs.modal')\n    }\n  }\n\n  Modal.prototype.resize = function () {\n    if (this.isShown) {\n      $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))\n    } else {\n      $(window).off('resize.bs.modal')\n    }\n  }\n\n  Modal.prototype.hideModal = function () {\n    var that = this\n    this.$element.hide()\n    this.backdrop(function () {\n      that.$body.removeClass('modal-open')\n      that.resetAdjustments()\n      that.resetScrollbar()\n      that.$element.trigger('hidden.bs.modal')\n    })\n  }\n\n  Modal.prototype.removeBackdrop = function () {\n    this.$backdrop && this.$backdrop.remove()\n    this.$backdrop = null\n  }\n\n  Modal.prototype.backdrop = function (callback) {\n    var that = this\n    var animate = this.$element.hasClass('fade') ? 'fade' : ''\n\n    if (this.isShown && this.options.backdrop) {\n      var doAnimate = $.support.transition && animate\n\n      this.$backdrop = $('<div class=\"modal-backdrop ' + animate + '\" />')\n        .prependTo(this.$element)\n        .on('click.dismiss.bs.modal', $.proxy(function (e) {\n          if (e.target !== e.currentTarget) return\n          this.options.backdrop == 'static'\n            ? this.$element[0].focus.call(this.$element[0])\n            : this.hide.call(this)\n        }, this))\n\n      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow\n\n      this.$backdrop.addClass('in')\n\n      if (!callback) return\n\n      doAnimate ?\n        this.$backdrop\n          .one('bsTransitionEnd', callback)\n          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :\n        callback()\n\n    } else if (!this.isShown && this.$backdrop) {\n      this.$backdrop.removeClass('in')\n\n      var callbackRemove = function () {\n        that.removeBackdrop()\n        callback && callback()\n      }\n      $.support.transition && this.$element.hasClass('fade') ?\n        this.$backdrop\n          .one('bsTransitionEnd', callbackRemove)\n          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :\n        callbackRemove()\n\n    } else if (callback) {\n      callback()\n    }\n  }\n\n  // these following methods are used to handle overflowing modals\n\n  Modal.prototype.handleUpdate = function () {\n    if (this.options.backdrop) this.adjustBackdrop()\n    this.adjustDialog()\n  }\n\n  Modal.prototype.adjustBackdrop = function () {\n    this.$backdrop\n      .css('height', 0)\n      .css('height', this.$element[0].scrollHeight)\n  }\n\n  Modal.prototype.adjustDialog = function () {\n    var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight\n\n    this.$element.css({\n      paddingLeft:  !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',\n      paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''\n    })\n  }\n\n  Modal.prototype.resetAdjustments = function () {\n    this.$element.css({\n      paddingLeft: '',\n      paddingRight: ''\n    })\n  }\n\n  Modal.prototype.checkScrollbar = function () {\n    this.bodyIsOverflowing = document.body.scrollHeight > document.documentElement.clientHeight\n    this.scrollbarWidth = this.measureScrollbar()\n  }\n\n  Modal.prototype.setScrollbar = function () {\n    var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)\n    if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)\n  }\n\n  Modal.prototype.resetScrollbar = function () {\n    this.$body.css('padding-right', '')\n  }\n\n  Modal.prototype.measureScrollbar = function () { // thx walsh\n    var scrollDiv = document.createElement('div')\n    scrollDiv.className = 'modal-scrollbar-measure'\n    this.$body.append(scrollDiv)\n    var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth\n    this.$body[0].removeChild(scrollDiv)\n    return scrollbarWidth\n  }\n\n\n  // MODAL PLUGIN DEFINITION\n  // =======================\n\n  function Plugin(option, _relatedTarget) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.modal')\n      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)\n\n      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))\n      if (typeof option == 'string') data[option](_relatedTarget)\n      else if (options.show) data.show(_relatedTarget)\n    })\n  }\n\n  var old = $.fn.modal\n\n  $.fn.modal             = Plugin\n  $.fn.modal.Constructor = Modal\n\n\n  // MODAL NO CONFLICT\n  // =================\n\n  $.fn.modal.noConflict = function () {\n    $.fn.modal = old\n    return this\n  }\n\n\n  // MODAL DATA-API\n  // ==============\n\n  $(document).on('click.bs.modal.data-api', '[data-toggle=\"modal\"]', function (e) {\n    var $this   = $(this)\n    var href    = $this.attr('href')\n    var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\\s]+$)/, ''))) // strip for ie7\n    var option  = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())\n\n    if ($this.is('a')) e.preventDefault()\n\n    $target.one('show.bs.modal', function (showEvent) {\n      if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown\n      $target.one('hidden.bs.modal', function () {\n        $this.is(':visible') && $this.trigger('focus')\n      })\n    })\n    Plugin.call($target, option, this)\n  })\n\n}(jQuery);\n"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/popover.js",
    "content": "/* ========================================================================\n * Bootstrap: popover.js v3.3.1\n * http://getbootstrap.com/javascript/#popovers\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // POPOVER PUBLIC CLASS DEFINITION\n  // ===============================\n\n  var Popover = function (element, options) {\n    this.init('popover', element, options)\n  }\n\n  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')\n\n  Popover.VERSION  = '3.3.1'\n\n  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {\n    placement: 'right',\n    trigger: 'click',\n    content: '',\n    template: '<div class=\"popover\" role=\"tooltip\"><div class=\"arrow\"></div><h3 class=\"popover-title\"></h3><div class=\"popover-content\"></div></div>'\n  })\n\n\n  // NOTE: POPOVER EXTENDS tooltip.js\n  // ================================\n\n  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)\n\n  Popover.prototype.constructor = Popover\n\n  Popover.prototype.getDefaults = function () {\n    return Popover.DEFAULTS\n  }\n\n  Popover.prototype.setContent = function () {\n    var $tip    = this.tip()\n    var title   = this.getTitle()\n    var content = this.getContent()\n\n    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)\n    $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events\n      this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'\n    ](content)\n\n    $tip.removeClass('fade top bottom left right in')\n\n    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do\n    // this manually by checking the contents.\n    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()\n  }\n\n  Popover.prototype.hasContent = function () {\n    return this.getTitle() || this.getContent()\n  }\n\n  Popover.prototype.getContent = function () {\n    var $e = this.$element\n    var o  = this.options\n\n    return $e.attr('data-content')\n      || (typeof o.content == 'function' ?\n            o.content.call($e[0]) :\n            o.content)\n  }\n\n  Popover.prototype.arrow = function () {\n    return (this.$arrow = this.$arrow || this.tip().find('.arrow'))\n  }\n\n  Popover.prototype.tip = function () {\n    if (!this.$tip) this.$tip = $(this.options.template)\n    return this.$tip\n  }\n\n\n  // POPOVER PLUGIN DEFINITION\n  // =========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this    = $(this)\n      var data     = $this.data('bs.popover')\n      var options  = typeof option == 'object' && option\n      var selector = options && options.selector\n\n      if (!data && option == 'destroy') return\n      if (selector) {\n        if (!data) $this.data('bs.popover', (data = {}))\n        if (!data[selector]) data[selector] = new Popover(this, options)\n      } else {\n        if (!data) $this.data('bs.popover', (data = new Popover(this, options)))\n      }\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.popover\n\n  $.fn.popover             = Plugin\n  $.fn.popover.Constructor = Popover\n\n\n  // POPOVER NO CONFLICT\n  // ===================\n\n  $.fn.popover.noConflict = function () {\n    $.fn.popover = old\n    return this\n  }\n\n}(jQuery);\n"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/scrollspy.js",
    "content": "/* ========================================================================\n * Bootstrap: scrollspy.js v3.3.1\n * http://getbootstrap.com/javascript/#scrollspy\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // SCROLLSPY CLASS DEFINITION\n  // ==========================\n\n  function ScrollSpy(element, options) {\n    var process  = $.proxy(this.process, this)\n\n    this.$body          = $('body')\n    this.$scrollElement = $(element).is('body') ? $(window) : $(element)\n    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)\n    this.selector       = (this.options.target || '') + ' .nav li > a'\n    this.offsets        = []\n    this.targets        = []\n    this.activeTarget   = null\n    this.scrollHeight   = 0\n\n    this.$scrollElement.on('scroll.bs.scrollspy', process)\n    this.refresh()\n    this.process()\n  }\n\n  ScrollSpy.VERSION  = '3.3.1'\n\n  ScrollSpy.DEFAULTS = {\n    offset: 10\n  }\n\n  ScrollSpy.prototype.getScrollHeight = function () {\n    return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)\n  }\n\n  ScrollSpy.prototype.refresh = function () {\n    var offsetMethod = 'offset'\n    var offsetBase   = 0\n\n    if (!$.isWindow(this.$scrollElement[0])) {\n      offsetMethod = 'position'\n      offsetBase   = this.$scrollElement.scrollTop()\n    }\n\n    this.offsets = []\n    this.targets = []\n    this.scrollHeight = this.getScrollHeight()\n\n    var self     = this\n\n    this.$body\n      .find(this.selector)\n      .map(function () {\n        var $el   = $(this)\n        var href  = $el.data('target') || $el.attr('href')\n        var $href = /^#./.test(href) && $(href)\n\n        return ($href\n          && $href.length\n          && $href.is(':visible')\n          && [[$href[offsetMethod]().top + offsetBase, href]]) || null\n      })\n      .sort(function (a, b) { return a[0] - b[0] })\n      .each(function () {\n        self.offsets.push(this[0])\n        self.targets.push(this[1])\n      })\n  }\n\n  ScrollSpy.prototype.process = function () {\n    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset\n    var scrollHeight = this.getScrollHeight()\n    var maxScroll    = this.options.offset + scrollHeight - this.$scrollElement.height()\n    var offsets      = this.offsets\n    var targets      = this.targets\n    var activeTarget = this.activeTarget\n    var i\n\n    if (this.scrollHeight != scrollHeight) {\n      this.refresh()\n    }\n\n    if (scrollTop >= maxScroll) {\n      return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)\n    }\n\n    if (activeTarget && scrollTop < offsets[0]) {\n      this.activeTarget = null\n      return this.clear()\n    }\n\n    for (i = offsets.length; i--;) {\n      activeTarget != targets[i]\n        && scrollTop >= offsets[i]\n        && (!offsets[i + 1] || scrollTop <= offsets[i + 1])\n        && this.activate(targets[i])\n    }\n  }\n\n  ScrollSpy.prototype.activate = function (target) {\n    this.activeTarget = target\n\n    this.clear()\n\n    var selector = this.selector +\n        '[data-target=\"' + target + '\"],' +\n        this.selector + '[href=\"' + target + '\"]'\n\n    var active = $(selector)\n      .parents('li')\n      .addClass('active')\n\n    if (active.parent('.dropdown-menu').length) {\n      active = active\n        .closest('li.dropdown')\n        .addClass('active')\n    }\n\n    active.trigger('activate.bs.scrollspy')\n  }\n\n  ScrollSpy.prototype.clear = function () {\n    $(this.selector)\n      .parentsUntil(this.options.target, '.active')\n      .removeClass('active')\n  }\n\n\n  // SCROLLSPY PLUGIN DEFINITION\n  // ===========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.scrollspy')\n      var options = typeof option == 'object' && option\n\n      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.scrollspy\n\n  $.fn.scrollspy             = Plugin\n  $.fn.scrollspy.Constructor = ScrollSpy\n\n\n  // SCROLLSPY NO CONFLICT\n  // =====================\n\n  $.fn.scrollspy.noConflict = function () {\n    $.fn.scrollspy = old\n    return this\n  }\n\n\n  // SCROLLSPY DATA-API\n  // ==================\n\n  $(window).on('load.bs.scrollspy.data-api', function () {\n    $('[data-spy=\"scroll\"]').each(function () {\n      var $spy = $(this)\n      Plugin.call($spy, $spy.data())\n    })\n  })\n\n}(jQuery);\n"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/tab.js",
    "content": "/* ========================================================================\n * Bootstrap: tab.js v3.3.1\n * http://getbootstrap.com/javascript/#tabs\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // TAB CLASS DEFINITION\n  // ====================\n\n  var Tab = function (element) {\n    this.element = $(element)\n  }\n\n  Tab.VERSION = '3.3.1'\n\n  Tab.TRANSITION_DURATION = 150\n\n  Tab.prototype.show = function () {\n    var $this    = this.element\n    var $ul      = $this.closest('ul:not(.dropdown-menu)')\n    var selector = $this.data('target')\n\n    if (!selector) {\n      selector = $this.attr('href')\n      selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, '') // strip for ie7\n    }\n\n    if ($this.parent('li').hasClass('active')) return\n\n    var $previous = $ul.find('.active:last a')\n    var hideEvent = $.Event('hide.bs.tab', {\n      relatedTarget: $this[0]\n    })\n    var showEvent = $.Event('show.bs.tab', {\n      relatedTarget: $previous[0]\n    })\n\n    $previous.trigger(hideEvent)\n    $this.trigger(showEvent)\n\n    if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return\n\n    var $target = $(selector)\n\n    this.activate($this.closest('li'), $ul)\n    this.activate($target, $target.parent(), function () {\n      $previous.trigger({\n        type: 'hidden.bs.tab',\n        relatedTarget: $this[0]\n      })\n      $this.trigger({\n        type: 'shown.bs.tab',\n        relatedTarget: $previous[0]\n      })\n    })\n  }\n\n  Tab.prototype.activate = function (element, container, callback) {\n    var $active    = container.find('> .active')\n    var transition = callback\n      && $.support.transition\n      && (($active.length && $active.hasClass('fade')) || !!container.find('> .fade').length)\n\n    function next() {\n      $active\n        .removeClass('active')\n        .find('> .dropdown-menu > .active')\n          .removeClass('active')\n        .end()\n        .find('[data-toggle=\"tab\"]')\n          .attr('aria-expanded', false)\n\n      element\n        .addClass('active')\n        .find('[data-toggle=\"tab\"]')\n          .attr('aria-expanded', true)\n\n      if (transition) {\n        element[0].offsetWidth // reflow for transition\n        element.addClass('in')\n      } else {\n        element.removeClass('fade')\n      }\n\n      if (element.parent('.dropdown-menu')) {\n        element\n          .closest('li.dropdown')\n            .addClass('active')\n          .end()\n          .find('[data-toggle=\"tab\"]')\n            .attr('aria-expanded', true)\n      }\n\n      callback && callback()\n    }\n\n    $active.length && transition ?\n      $active\n        .one('bsTransitionEnd', next)\n        .emulateTransitionEnd(Tab.TRANSITION_DURATION) :\n      next()\n\n    $active.removeClass('in')\n  }\n\n\n  // TAB PLUGIN DEFINITION\n  // =====================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this = $(this)\n      var data  = $this.data('bs.tab')\n\n      if (!data) $this.data('bs.tab', (data = new Tab(this)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.tab\n\n  $.fn.tab             = Plugin\n  $.fn.tab.Constructor = Tab\n\n\n  // TAB NO CONFLICT\n  // ===============\n\n  $.fn.tab.noConflict = function () {\n    $.fn.tab = old\n    return this\n  }\n\n\n  // TAB DATA-API\n  // ============\n\n  var clickHandler = function (e) {\n    e.preventDefault()\n    Plugin.call($(this), 'show')\n  }\n\n  $(document)\n    .on('click.bs.tab.data-api', '[data-toggle=\"tab\"]', clickHandler)\n    .on('click.bs.tab.data-api', '[data-toggle=\"pill\"]', clickHandler)\n\n}(jQuery);\n"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/tooltip.js",
    "content": "/* ========================================================================\n * Bootstrap: tooltip.js v3.3.1\n * http://getbootstrap.com/javascript/#tooltip\n * Inspired by the original jQuery.tipsy by Jason Frame\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // TOOLTIP PUBLIC CLASS DEFINITION\n  // ===============================\n\n  var Tooltip = function (element, options) {\n    this.type       =\n    this.options    =\n    this.enabled    =\n    this.timeout    =\n    this.hoverState =\n    this.$element   = null\n\n    this.init('tooltip', element, options)\n  }\n\n  Tooltip.VERSION  = '3.3.1'\n\n  Tooltip.TRANSITION_DURATION = 150\n\n  Tooltip.DEFAULTS = {\n    animation: true,\n    placement: 'top',\n    selector: false,\n    template: '<div class=\"tooltip\" role=\"tooltip\"><div class=\"tooltip-arrow\"></div><div class=\"tooltip-inner\"></div></div>',\n    trigger: 'hover focus',\n    title: '',\n    delay: 0,\n    html: false,\n    container: false,\n    viewport: {\n      selector: 'body',\n      padding: 0\n    }\n  }\n\n  Tooltip.prototype.init = function (type, element, options) {\n    this.enabled   = true\n    this.type      = type\n    this.$element  = $(element)\n    this.options   = this.getOptions(options)\n    this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)\n\n    var triggers = this.options.trigger.split(' ')\n\n    for (var i = triggers.length; i--;) {\n      var trigger = triggers[i]\n\n      if (trigger == 'click') {\n        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))\n      } else if (trigger != 'manual') {\n        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'\n        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'\n\n        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))\n        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))\n      }\n    }\n\n    this.options.selector ?\n      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :\n      this.fixTitle()\n  }\n\n  Tooltip.prototype.getDefaults = function () {\n    return Tooltip.DEFAULTS\n  }\n\n  Tooltip.prototype.getOptions = function (options) {\n    options = $.extend({}, this.getDefaults(), this.$element.data(), options)\n\n    if (options.delay && typeof options.delay == 'number') {\n      options.delay = {\n        show: options.delay,\n        hide: options.delay\n      }\n    }\n\n    return options\n  }\n\n  Tooltip.prototype.getDelegateOptions = function () {\n    var options  = {}\n    var defaults = this.getDefaults()\n\n    this._options && $.each(this._options, function (key, value) {\n      if (defaults[key] != value) options[key] = value\n    })\n\n    return options\n  }\n\n  Tooltip.prototype.enter = function (obj) {\n    var self = obj instanceof this.constructor ?\n      obj : $(obj.currentTarget).data('bs.' + this.type)\n\n    if (self && self.$tip && self.$tip.is(':visible')) {\n      self.hoverState = 'in'\n      return\n    }\n\n    if (!self) {\n      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())\n      $(obj.currentTarget).data('bs.' + this.type, self)\n    }\n\n    clearTimeout(self.timeout)\n\n    self.hoverState = 'in'\n\n    if (!self.options.delay || !self.options.delay.show) return self.show()\n\n    self.timeout = setTimeout(function () {\n      if (self.hoverState == 'in') self.show()\n    }, self.options.delay.show)\n  }\n\n  Tooltip.prototype.leave = function (obj) {\n    var self = obj instanceof this.constructor ?\n      obj : $(obj.currentTarget).data('bs.' + this.type)\n\n    if (!self) {\n      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())\n      $(obj.currentTarget).data('bs.' + this.type, self)\n    }\n\n    clearTimeout(self.timeout)\n\n    self.hoverState = 'out'\n\n    if (!self.options.delay || !self.options.delay.hide) return self.hide()\n\n    self.timeout = setTimeout(function () {\n      if (self.hoverState == 'out') self.hide()\n    }, self.options.delay.hide)\n  }\n\n  Tooltip.prototype.show = function () {\n    var e = $.Event('show.bs.' + this.type)\n\n    if (this.hasContent() && this.enabled) {\n      this.$element.trigger(e)\n\n      var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])\n      if (e.isDefaultPrevented() || !inDom) return\n      var that = this\n\n      var $tip = this.tip()\n\n      var tipId = this.getUID(this.type)\n\n      this.setContent()\n      $tip.attr('id', tipId)\n      this.$element.attr('aria-describedby', tipId)\n\n      if (this.options.animation) $tip.addClass('fade')\n\n      var placement = typeof this.options.placement == 'function' ?\n        this.options.placement.call(this, $tip[0], this.$element[0]) :\n        this.options.placement\n\n      var autoToken = /\\s?auto?\\s?/i\n      var autoPlace = autoToken.test(placement)\n      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'\n\n      $tip\n        .detach()\n        .css({ top: 0, left: 0, display: 'block' })\n        .addClass(placement)\n        .data('bs.' + this.type, this)\n\n      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)\n\n      var pos          = this.getPosition()\n      var actualWidth  = $tip[0].offsetWidth\n      var actualHeight = $tip[0].offsetHeight\n\n      if (autoPlace) {\n        var orgPlacement = placement\n        var $container   = this.options.container ? $(this.options.container) : this.$element.parent()\n        var containerDim = this.getPosition($container)\n\n        placement = placement == 'bottom' && pos.bottom + actualHeight > containerDim.bottom ? 'top'    :\n                    placement == 'top'    && pos.top    - actualHeight < containerDim.top    ? 'bottom' :\n                    placement == 'right'  && pos.right  + actualWidth  > containerDim.width  ? 'left'   :\n                    placement == 'left'   && pos.left   - actualWidth  < containerDim.left   ? 'right'  :\n                    placement\n\n        $tip\n          .removeClass(orgPlacement)\n          .addClass(placement)\n      }\n\n      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)\n\n      this.applyPlacement(calculatedOffset, placement)\n\n      var complete = function () {\n        var prevHoverState = that.hoverState\n        that.$element.trigger('shown.bs.' + that.type)\n        that.hoverState = null\n\n        if (prevHoverState == 'out') that.leave(that)\n      }\n\n      $.support.transition && this.$tip.hasClass('fade') ?\n        $tip\n          .one('bsTransitionEnd', complete)\n          .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :\n        complete()\n    }\n  }\n\n  Tooltip.prototype.applyPlacement = function (offset, placement) {\n    var $tip   = this.tip()\n    var width  = $tip[0].offsetWidth\n    var height = $tip[0].offsetHeight\n\n    // manually read margins because getBoundingClientRect includes difference\n    var marginTop = parseInt($tip.css('margin-top'), 10)\n    var marginLeft = parseInt($tip.css('margin-left'), 10)\n\n    // we must check for NaN for ie 8/9\n    if (isNaN(marginTop))  marginTop  = 0\n    if (isNaN(marginLeft)) marginLeft = 0\n\n    offset.top  = offset.top  + marginTop\n    offset.left = offset.left + marginLeft\n\n    // $.fn.offset doesn't round pixel values\n    // so we use setOffset directly with our own function B-0\n    $.offset.setOffset($tip[0], $.extend({\n      using: function (props) {\n        $tip.css({\n          top: Math.round(props.top),\n          left: Math.round(props.left)\n        })\n      }\n    }, offset), 0)\n\n    $tip.addClass('in')\n\n    // check to see if placing tip in new offset caused the tip to resize itself\n    var actualWidth  = $tip[0].offsetWidth\n    var actualHeight = $tip[0].offsetHeight\n\n    if (placement == 'top' && actualHeight != height) {\n      offset.top = offset.top + height - actualHeight\n    }\n\n    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)\n\n    if (delta.left) offset.left += delta.left\n    else offset.top += delta.top\n\n    var isVertical          = /top|bottom/.test(placement)\n    var arrowDelta          = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight\n    var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'\n\n    $tip.offset(offset)\n    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)\n  }\n\n  Tooltip.prototype.replaceArrow = function (delta, dimension, isHorizontal) {\n    this.arrow()\n      .css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')\n      .css(isHorizontal ? 'top' : 'left', '')\n  }\n\n  Tooltip.prototype.setContent = function () {\n    var $tip  = this.tip()\n    var title = this.getTitle()\n\n    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)\n    $tip.removeClass('fade in top bottom left right')\n  }\n\n  Tooltip.prototype.hide = function (callback) {\n    var that = this\n    var $tip = this.tip()\n    var e    = $.Event('hide.bs.' + this.type)\n\n    function complete() {\n      if (that.hoverState != 'in') $tip.detach()\n      that.$element\n        .removeAttr('aria-describedby')\n        .trigger('hidden.bs.' + that.type)\n      callback && callback()\n    }\n\n    this.$element.trigger(e)\n\n    if (e.isDefaultPrevented()) return\n\n    $tip.removeClass('in')\n\n    $.support.transition && this.$tip.hasClass('fade') ?\n      $tip\n        .one('bsTransitionEnd', complete)\n        .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :\n      complete()\n\n    this.hoverState = null\n\n    return this\n  }\n\n  Tooltip.prototype.fixTitle = function () {\n    var $e = this.$element\n    if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') {\n      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')\n    }\n  }\n\n  Tooltip.prototype.hasContent = function () {\n    return this.getTitle()\n  }\n\n  Tooltip.prototype.getPosition = function ($element) {\n    $element   = $element || this.$element\n\n    var el     = $element[0]\n    var isBody = el.tagName == 'BODY'\n\n    var elRect    = el.getBoundingClientRect()\n    if (elRect.width == null) {\n      // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093\n      elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })\n    }\n    var elOffset  = isBody ? { top: 0, left: 0 } : $element.offset()\n    var scroll    = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }\n    var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null\n\n    return $.extend({}, elRect, scroll, outerDims, elOffset)\n  }\n\n  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {\n    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2  } :\n           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2  } :\n           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :\n        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width   }\n\n  }\n\n  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {\n    var delta = { top: 0, left: 0 }\n    if (!this.$viewport) return delta\n\n    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0\n    var viewportDimensions = this.getPosition(this.$viewport)\n\n    if (/right|left/.test(placement)) {\n      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll\n      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight\n      if (topEdgeOffset < viewportDimensions.top) { // top overflow\n        delta.top = viewportDimensions.top - topEdgeOffset\n      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow\n        delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset\n      }\n    } else {\n      var leftEdgeOffset  = pos.left - viewportPadding\n      var rightEdgeOffset = pos.left + viewportPadding + actualWidth\n      if (leftEdgeOffset < viewportDimensions.left) { // left overflow\n        delta.left = viewportDimensions.left - leftEdgeOffset\n      } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow\n        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset\n      }\n    }\n\n    return delta\n  }\n\n  Tooltip.prototype.getTitle = function () {\n    var title\n    var $e = this.$element\n    var o  = this.options\n\n    title = $e.attr('data-original-title')\n      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)\n\n    return title\n  }\n\n  Tooltip.prototype.getUID = function (prefix) {\n    do prefix += ~~(Math.random() * 1000000)\n    while (document.getElementById(prefix))\n    return prefix\n  }\n\n  Tooltip.prototype.tip = function () {\n    return (this.$tip = this.$tip || $(this.options.template))\n  }\n\n  Tooltip.prototype.arrow = function () {\n    return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))\n  }\n\n  Tooltip.prototype.enable = function () {\n    this.enabled = true\n  }\n\n  Tooltip.prototype.disable = function () {\n    this.enabled = false\n  }\n\n  Tooltip.prototype.toggleEnabled = function () {\n    this.enabled = !this.enabled\n  }\n\n  Tooltip.prototype.toggle = function (e) {\n    var self = this\n    if (e) {\n      self = $(e.currentTarget).data('bs.' + this.type)\n      if (!self) {\n        self = new this.constructor(e.currentTarget, this.getDelegateOptions())\n        $(e.currentTarget).data('bs.' + this.type, self)\n      }\n    }\n\n    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)\n  }\n\n  Tooltip.prototype.destroy = function () {\n    var that = this\n    clearTimeout(this.timeout)\n    this.hide(function () {\n      that.$element.off('.' + that.type).removeData('bs.' + that.type)\n    })\n  }\n\n\n  // TOOLTIP PLUGIN DEFINITION\n  // =========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this    = $(this)\n      var data     = $this.data('bs.tooltip')\n      var options  = typeof option == 'object' && option\n      var selector = options && options.selector\n\n      if (!data && option == 'destroy') return\n      if (selector) {\n        if (!data) $this.data('bs.tooltip', (data = {}))\n        if (!data[selector]) data[selector] = new Tooltip(this, options)\n      } else {\n        if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))\n      }\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.tooltip\n\n  $.fn.tooltip             = Plugin\n  $.fn.tooltip.Constructor = Tooltip\n\n\n  // TOOLTIP NO CONFLICT\n  // ===================\n\n  $.fn.tooltip.noConflict = function () {\n    $.fn.tooltip = old\n    return this\n  }\n\n}(jQuery);\n"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/transition.js",
    "content": "/* ========================================================================\n * Bootstrap: transition.js v3.3.1\n * http://getbootstrap.com/javascript/#transitions\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)\n  // ============================================================\n\n  function transitionEnd() {\n    var el = document.createElement('bootstrap')\n\n    var transEndEventNames = {\n      WebkitTransition : 'webkitTransitionEnd',\n      MozTransition    : 'transitionend',\n      OTransition      : 'oTransitionEnd otransitionend',\n      transition       : 'transitionend'\n    }\n\n    for (var name in transEndEventNames) {\n      if (el.style[name] !== undefined) {\n        return { end: transEndEventNames[name] }\n      }\n    }\n\n    return false // explicit for ie8 (  ._.)\n  }\n\n  // http://blog.alexmaccaw.com/css-transitions\n  $.fn.emulateTransitionEnd = function (duration) {\n    var called = false\n    var $el = this\n    $(this).one('bsTransitionEnd', function () { called = true })\n    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }\n    setTimeout(callback, duration)\n    return this\n  }\n\n  $(function () {\n    $.support.transition = transitionEnd()\n\n    if (!$.support.transition) return\n\n    $.event.special.bsTransitionEnd = {\n      bindType: $.support.transition.end,\n      delegateType: $.support.transition.end,\n      handle: function (e) {\n        if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)\n      }\n    }\n  })\n\n}(jQuery);\n"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap.js",
    "content": "/* ========================================================================\n * Bootstrap: affix.js v3.3.1\n * http://getbootstrap.com/javascript/#affix\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // AFFIX CLASS DEFINITION\n  // ======================\n\n  var Affix = function (element, options) {\n    this.options = $.extend({}, Affix.DEFAULTS, options)\n\n    this.$target = $(this.options.target)\n      .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))\n      .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))\n\n    this.$element     = $(element)\n    this.affixed      =\n    this.unpin        =\n    this.pinnedOffset = null\n\n    this.checkPosition()\n  }\n\n  Affix.VERSION  = '3.3.1'\n\n  Affix.RESET    = 'affix affix-top affix-bottom'\n\n  Affix.DEFAULTS = {\n    offset: 0,\n    target: window\n  }\n\n  Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {\n    var scrollTop    = this.$target.scrollTop()\n    var position     = this.$element.offset()\n    var targetHeight = this.$target.height()\n\n    if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false\n\n    if (this.affixed == 'bottom') {\n      if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'\n      return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'\n    }\n\n    var initializing   = this.affixed == null\n    var colliderTop    = initializing ? scrollTop : position.top\n    var colliderHeight = initializing ? targetHeight : height\n\n    if (offsetTop != null && colliderTop <= offsetTop) return 'top'\n    if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'\n\n    return false\n  }\n\n  Affix.prototype.getPinnedOffset = function () {\n    if (this.pinnedOffset) return this.pinnedOffset\n    this.$element.removeClass(Affix.RESET).addClass('affix')\n    var scrollTop = this.$target.scrollTop()\n    var position  = this.$element.offset()\n    return (this.pinnedOffset = position.top - scrollTop)\n  }\n\n  Affix.prototype.checkPositionWithEventLoop = function () {\n    setTimeout($.proxy(this.checkPosition, this), 1)\n  }\n\n  Affix.prototype.checkPosition = function () {\n    if (!this.$element.is(':visible')) return\n\n    var height       = this.$element.height()\n    var offset       = this.options.offset\n    var offsetTop    = offset.top\n    var offsetBottom = offset.bottom\n    var scrollHeight = $('body').height()\n\n    if (typeof offset != 'object')         offsetBottom = offsetTop = offset\n    if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)\n    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)\n\n    var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)\n\n    if (this.affixed != affix) {\n      if (this.unpin != null) this.$element.css('top', '')\n\n      var affixType = 'affix' + (affix ? '-' + affix : '')\n      var e         = $.Event(affixType + '.bs.affix')\n\n      this.$element.trigger(e)\n\n      if (e.isDefaultPrevented()) return\n\n      this.affixed = affix\n      this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null\n\n      this.$element\n        .removeClass(Affix.RESET)\n        .addClass(affixType)\n        .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')\n    }\n\n    if (affix == 'bottom') {\n      this.$element.offset({\n        top: scrollHeight - height - offsetBottom\n      })\n    }\n  }\n\n\n  // AFFIX PLUGIN DEFINITION\n  // =======================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.affix')\n      var options = typeof option == 'object' && option\n\n      if (!data) $this.data('bs.affix', (data = new Affix(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.affix\n\n  $.fn.affix             = Plugin\n  $.fn.affix.Constructor = Affix\n\n\n  // AFFIX NO CONFLICT\n  // =================\n\n  $.fn.affix.noConflict = function () {\n    $.fn.affix = old\n    return this\n  }\n\n\n  // AFFIX DATA-API\n  // ==============\n\n  $(window).on('load', function () {\n    $('[data-spy=\"affix\"]').each(function () {\n      var $spy = $(this)\n      var data = $spy.data()\n\n      data.offset = data.offset || {}\n\n      if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom\n      if (data.offsetTop    != null) data.offset.top    = data.offsetTop\n\n      Plugin.call($spy, data)\n    })\n  })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: alert.js v3.3.1\n * http://getbootstrap.com/javascript/#alerts\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // ALERT CLASS DEFINITION\n  // ======================\n\n  var dismiss = '[data-dismiss=\"alert\"]'\n  var Alert   = function (el) {\n    $(el).on('click', dismiss, this.close)\n  }\n\n  Alert.VERSION = '3.3.1'\n\n  Alert.TRANSITION_DURATION = 150\n\n  Alert.prototype.close = function (e) {\n    var $this    = $(this)\n    var selector = $this.attr('data-target')\n\n    if (!selector) {\n      selector = $this.attr('href')\n      selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, '') // strip for ie7\n    }\n\n    var $parent = $(selector)\n\n    if (e) e.preventDefault()\n\n    if (!$parent.length) {\n      $parent = $this.closest('.alert')\n    }\n\n    $parent.trigger(e = $.Event('close.bs.alert'))\n\n    if (e.isDefaultPrevented()) return\n\n    $parent.removeClass('in')\n\n    function removeElement() {\n      // detach from parent, fire event then clean up data\n      $parent.detach().trigger('closed.bs.alert').remove()\n    }\n\n    $.support.transition && $parent.hasClass('fade') ?\n      $parent\n        .one('bsTransitionEnd', removeElement)\n        .emulateTransitionEnd(Alert.TRANSITION_DURATION) :\n      removeElement()\n  }\n\n\n  // ALERT PLUGIN DEFINITION\n  // =======================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this = $(this)\n      var data  = $this.data('bs.alert')\n\n      if (!data) $this.data('bs.alert', (data = new Alert(this)))\n      if (typeof option == 'string') data[option].call($this)\n    })\n  }\n\n  var old = $.fn.alert\n\n  $.fn.alert             = Plugin\n  $.fn.alert.Constructor = Alert\n\n\n  // ALERT NO CONFLICT\n  // =================\n\n  $.fn.alert.noConflict = function () {\n    $.fn.alert = old\n    return this\n  }\n\n\n  // ALERT DATA-API\n  // ==============\n\n  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: button.js v3.3.1\n * http://getbootstrap.com/javascript/#buttons\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // BUTTON PUBLIC CLASS DEFINITION\n  // ==============================\n\n  var Button = function (element, options) {\n    this.$element  = $(element)\n    this.options   = $.extend({}, Button.DEFAULTS, options)\n    this.isLoading = false\n  }\n\n  Button.VERSION  = '3.3.1'\n\n  Button.DEFAULTS = {\n    loadingText: 'loading...'\n  }\n\n  Button.prototype.setState = function (state) {\n    var d    = 'disabled'\n    var $el  = this.$element\n    var val  = $el.is('input') ? 'val' : 'html'\n    var data = $el.data()\n\n    state = state + 'Text'\n\n    if (data.resetText == null) $el.data('resetText', $el[val]())\n\n    // push to event loop to allow forms to submit\n    setTimeout($.proxy(function () {\n      $el[val](data[state] == null ? this.options[state] : data[state])\n\n      if (state == 'loadingText') {\n        this.isLoading = true\n        $el.addClass(d).attr(d, d)\n      } else if (this.isLoading) {\n        this.isLoading = false\n        $el.removeClass(d).removeAttr(d)\n      }\n    }, this), 0)\n  }\n\n  Button.prototype.toggle = function () {\n    var changed = true\n    var $parent = this.$element.closest('[data-toggle=\"buttons\"]')\n\n    if ($parent.length) {\n      var $input = this.$element.find('input')\n      if ($input.prop('type') == 'radio') {\n        if ($input.prop('checked') && this.$element.hasClass('active')) changed = false\n        else $parent.find('.active').removeClass('active')\n      }\n      if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change')\n    } else {\n      this.$element.attr('aria-pressed', !this.$element.hasClass('active'))\n    }\n\n    if (changed) this.$element.toggleClass('active')\n  }\n\n\n  // BUTTON PLUGIN DEFINITION\n  // ========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.button')\n      var options = typeof option == 'object' && option\n\n      if (!data) $this.data('bs.button', (data = new Button(this, options)))\n\n      if (option == 'toggle') data.toggle()\n      else if (option) data.setState(option)\n    })\n  }\n\n  var old = $.fn.button\n\n  $.fn.button             = Plugin\n  $.fn.button.Constructor = Button\n\n\n  // BUTTON NO CONFLICT\n  // ==================\n\n  $.fn.button.noConflict = function () {\n    $.fn.button = old\n    return this\n  }\n\n\n  // BUTTON DATA-API\n  // ===============\n\n  $(document)\n    .on('click.bs.button.data-api', '[data-toggle^=\"button\"]', function (e) {\n      var $btn = $(e.target)\n      if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')\n      Plugin.call($btn, 'toggle')\n      e.preventDefault()\n    })\n    .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^=\"button\"]', function (e) {\n      $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))\n    })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: carousel.js v3.3.1\n * http://getbootstrap.com/javascript/#carousel\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // CAROUSEL CLASS DEFINITION\n  // =========================\n\n  var Carousel = function (element, options) {\n    this.$element    = $(element)\n    this.$indicators = this.$element.find('.carousel-indicators')\n    this.options     = options\n    this.paused      =\n    this.sliding     =\n    this.interval    =\n    this.$active     =\n    this.$items      = null\n\n    this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))\n\n    this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element\n      .on('mouseenter.bs.carousel', $.proxy(this.pause, this))\n      .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))\n  }\n\n  Carousel.VERSION  = '3.3.1'\n\n  Carousel.TRANSITION_DURATION = 600\n\n  Carousel.DEFAULTS = {\n    interval: 5000,\n    pause: 'hover',\n    wrap: true,\n    keyboard: true\n  }\n\n  Carousel.prototype.keydown = function (e) {\n    if (/input|textarea/i.test(e.target.tagName)) return\n    switch (e.which) {\n      case 37: this.prev(); break\n      case 39: this.next(); break\n      default: return\n    }\n\n    e.preventDefault()\n  }\n\n  Carousel.prototype.cycle = function (e) {\n    e || (this.paused = false)\n\n    this.interval && clearInterval(this.interval)\n\n    this.options.interval\n      && !this.paused\n      && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))\n\n    return this\n  }\n\n  Carousel.prototype.getItemIndex = function (item) {\n    this.$items = item.parent().children('.item')\n    return this.$items.index(item || this.$active)\n  }\n\n  Carousel.prototype.getItemForDirection = function (direction, active) {\n    var delta = direction == 'prev' ? -1 : 1\n    var activeIndex = this.getItemIndex(active)\n    var itemIndex = (activeIndex + delta) % this.$items.length\n    return this.$items.eq(itemIndex)\n  }\n\n  Carousel.prototype.to = function (pos) {\n    var that        = this\n    var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))\n\n    if (pos > (this.$items.length - 1) || pos < 0) return\n\n    if (this.sliding)       return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, \"slid\"\n    if (activeIndex == pos) return this.pause().cycle()\n\n    return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))\n  }\n\n  Carousel.prototype.pause = function (e) {\n    e || (this.paused = true)\n\n    if (this.$element.find('.next, .prev').length && $.support.transition) {\n      this.$element.trigger($.support.transition.end)\n      this.cycle(true)\n    }\n\n    this.interval = clearInterval(this.interval)\n\n    return this\n  }\n\n  Carousel.prototype.next = function () {\n    if (this.sliding) return\n    return this.slide('next')\n  }\n\n  Carousel.prototype.prev = function () {\n    if (this.sliding) return\n    return this.slide('prev')\n  }\n\n  Carousel.prototype.slide = function (type, next) {\n    var $active   = this.$element.find('.item.active')\n    var $next     = next || this.getItemForDirection(type, $active)\n    var isCycling = this.interval\n    var direction = type == 'next' ? 'left' : 'right'\n    var fallback  = type == 'next' ? 'first' : 'last'\n    var that      = this\n\n    if (!$next.length) {\n      if (!this.options.wrap) return\n      $next = this.$element.find('.item')[fallback]()\n    }\n\n    if ($next.hasClass('active')) return (this.sliding = false)\n\n    var relatedTarget = $next[0]\n    var slideEvent = $.Event('slide.bs.carousel', {\n      relatedTarget: relatedTarget,\n      direction: direction\n    })\n    this.$element.trigger(slideEvent)\n    if (slideEvent.isDefaultPrevented()) return\n\n    this.sliding = true\n\n    isCycling && this.pause()\n\n    if (this.$indicators.length) {\n      this.$indicators.find('.active').removeClass('active')\n      var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])\n      $nextIndicator && $nextIndicator.addClass('active')\n    }\n\n    var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, \"slid\"\n    if ($.support.transition && this.$element.hasClass('slide')) {\n      $next.addClass(type)\n      $next[0].offsetWidth // force reflow\n      $active.addClass(direction)\n      $next.addClass(direction)\n      $active\n        .one('bsTransitionEnd', function () {\n          $next.removeClass([type, direction].join(' ')).addClass('active')\n          $active.removeClass(['active', direction].join(' '))\n          that.sliding = false\n          setTimeout(function () {\n            that.$element.trigger(slidEvent)\n          }, 0)\n        })\n        .emulateTransitionEnd(Carousel.TRANSITION_DURATION)\n    } else {\n      $active.removeClass('active')\n      $next.addClass('active')\n      this.sliding = false\n      this.$element.trigger(slidEvent)\n    }\n\n    isCycling && this.cycle()\n\n    return this\n  }\n\n\n  // CAROUSEL PLUGIN DEFINITION\n  // ==========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.carousel')\n      var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)\n      var action  = typeof option == 'string' ? option : options.slide\n\n      if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))\n      if (typeof option == 'number') data.to(option)\n      else if (action) data[action]()\n      else if (options.interval) data.pause().cycle()\n    })\n  }\n\n  var old = $.fn.carousel\n\n  $.fn.carousel             = Plugin\n  $.fn.carousel.Constructor = Carousel\n\n\n  // CAROUSEL NO CONFLICT\n  // ====================\n\n  $.fn.carousel.noConflict = function () {\n    $.fn.carousel = old\n    return this\n  }\n\n\n  // CAROUSEL DATA-API\n  // =================\n\n  var clickHandler = function (e) {\n    var href\n    var $this   = $(this)\n    var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '')) // strip for ie7\n    if (!$target.hasClass('carousel')) return\n    var options = $.extend({}, $target.data(), $this.data())\n    var slideIndex = $this.attr('data-slide-to')\n    if (slideIndex) options.interval = false\n\n    Plugin.call($target, options)\n\n    if (slideIndex) {\n      $target.data('bs.carousel').to(slideIndex)\n    }\n\n    e.preventDefault()\n  }\n\n  $(document)\n    .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)\n    .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)\n\n  $(window).on('load', function () {\n    $('[data-ride=\"carousel\"]').each(function () {\n      var $carousel = $(this)\n      Plugin.call($carousel, $carousel.data())\n    })\n  })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: collapse.js v3.3.1\n * http://getbootstrap.com/javascript/#collapse\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // COLLAPSE PUBLIC CLASS DEFINITION\n  // ================================\n\n  var Collapse = function (element, options) {\n    this.$element      = $(element)\n    this.options       = $.extend({}, Collapse.DEFAULTS, options)\n    this.$trigger      = $(this.options.trigger).filter('[href=\"#' + element.id + '\"], [data-target=\"#' + element.id + '\"]')\n    this.transitioning = null\n\n    if (this.options.parent) {\n      this.$parent = this.getParent()\n    } else {\n      this.addAriaAndCollapsedClass(this.$element, this.$trigger)\n    }\n\n    if (this.options.toggle) this.toggle()\n  }\n\n  Collapse.VERSION  = '3.3.1'\n\n  Collapse.TRANSITION_DURATION = 350\n\n  Collapse.DEFAULTS = {\n    toggle: true,\n    trigger: '[data-toggle=\"collapse\"]'\n  }\n\n  Collapse.prototype.dimension = function () {\n    var hasWidth = this.$element.hasClass('width')\n    return hasWidth ? 'width' : 'height'\n  }\n\n  Collapse.prototype.show = function () {\n    if (this.transitioning || this.$element.hasClass('in')) return\n\n    var activesData\n    var actives = this.$parent && this.$parent.find('> .panel').children('.in, .collapsing')\n\n    if (actives && actives.length) {\n      activesData = actives.data('bs.collapse')\n      if (activesData && activesData.transitioning) return\n    }\n\n    var startEvent = $.Event('show.bs.collapse')\n    this.$element.trigger(startEvent)\n    if (startEvent.isDefaultPrevented()) return\n\n    if (actives && actives.length) {\n      Plugin.call(actives, 'hide')\n      activesData || actives.data('bs.collapse', null)\n    }\n\n    var dimension = this.dimension()\n\n    this.$element\n      .removeClass('collapse')\n      .addClass('collapsing')[dimension](0)\n      .attr('aria-expanded', true)\n\n    this.$trigger\n      .removeClass('collapsed')\n      .attr('aria-expanded', true)\n\n    this.transitioning = 1\n\n    var complete = function () {\n      this.$element\n        .removeClass('collapsing')\n        .addClass('collapse in')[dimension]('')\n      this.transitioning = 0\n      this.$element\n        .trigger('shown.bs.collapse')\n    }\n\n    if (!$.support.transition) return complete.call(this)\n\n    var scrollSize = $.camelCase(['scroll', dimension].join('-'))\n\n    this.$element\n      .one('bsTransitionEnd', $.proxy(complete, this))\n      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])\n  }\n\n  Collapse.prototype.hide = function () {\n    if (this.transitioning || !this.$element.hasClass('in')) return\n\n    var startEvent = $.Event('hide.bs.collapse')\n    this.$element.trigger(startEvent)\n    if (startEvent.isDefaultPrevented()) return\n\n    var dimension = this.dimension()\n\n    this.$element[dimension](this.$element[dimension]())[0].offsetHeight\n\n    this.$element\n      .addClass('collapsing')\n      .removeClass('collapse in')\n      .attr('aria-expanded', false)\n\n    this.$trigger\n      .addClass('collapsed')\n      .attr('aria-expanded', false)\n\n    this.transitioning = 1\n\n    var complete = function () {\n      this.transitioning = 0\n      this.$element\n        .removeClass('collapsing')\n        .addClass('collapse')\n        .trigger('hidden.bs.collapse')\n    }\n\n    if (!$.support.transition) return complete.call(this)\n\n    this.$element\n      [dimension](0)\n      .one('bsTransitionEnd', $.proxy(complete, this))\n      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)\n  }\n\n  Collapse.prototype.toggle = function () {\n    this[this.$element.hasClass('in') ? 'hide' : 'show']()\n  }\n\n  Collapse.prototype.getParent = function () {\n    return $(this.options.parent)\n      .find('[data-toggle=\"collapse\"][data-parent=\"' + this.options.parent + '\"]')\n      .each($.proxy(function (i, element) {\n        var $element = $(element)\n        this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)\n      }, this))\n      .end()\n  }\n\n  Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {\n    var isOpen = $element.hasClass('in')\n\n    $element.attr('aria-expanded', isOpen)\n    $trigger\n      .toggleClass('collapsed', !isOpen)\n      .attr('aria-expanded', isOpen)\n  }\n\n  function getTargetFromTrigger($trigger) {\n    var href\n    var target = $trigger.attr('data-target')\n      || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '') // strip for ie7\n\n    return $(target)\n  }\n\n\n  // COLLAPSE PLUGIN DEFINITION\n  // ==========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.collapse')\n      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)\n\n      if (!data && options.toggle && option == 'show') options.toggle = false\n      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.collapse\n\n  $.fn.collapse             = Plugin\n  $.fn.collapse.Constructor = Collapse\n\n\n  // COLLAPSE NO CONFLICT\n  // ====================\n\n  $.fn.collapse.noConflict = function () {\n    $.fn.collapse = old\n    return this\n  }\n\n\n  // COLLAPSE DATA-API\n  // =================\n\n  $(document).on('click.bs.collapse.data-api', '[data-toggle=\"collapse\"]', function (e) {\n    var $this   = $(this)\n\n    if (!$this.attr('data-target')) e.preventDefault()\n\n    var $target = getTargetFromTrigger($this)\n    var data    = $target.data('bs.collapse')\n    var option  = data ? 'toggle' : $.extend({}, $this.data(), { trigger: this })\n\n    Plugin.call($target, option)\n  })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: dropdown.js v3.3.1\n * http://getbootstrap.com/javascript/#dropdowns\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // DROPDOWN CLASS DEFINITION\n  // =========================\n\n  var backdrop = '.dropdown-backdrop'\n  var toggle   = '[data-toggle=\"dropdown\"]'\n  var Dropdown = function (element) {\n    $(element).on('click.bs.dropdown', this.toggle)\n  }\n\n  Dropdown.VERSION = '3.3.1'\n\n  Dropdown.prototype.toggle = function (e) {\n    var $this = $(this)\n\n    if ($this.is('.disabled, :disabled')) return\n\n    var $parent  = getParent($this)\n    var isActive = $parent.hasClass('open')\n\n    clearMenus()\n\n    if (!isActive) {\n      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {\n        // if mobile we use a backdrop because click events don't delegate\n        $('<div class=\"dropdown-backdrop\"/>').insertAfter($(this)).on('click', clearMenus)\n      }\n\n      var relatedTarget = { relatedTarget: this }\n      $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))\n\n      if (e.isDefaultPrevented()) return\n\n      $this\n        .trigger('focus')\n        .attr('aria-expanded', 'true')\n\n      $parent\n        .toggleClass('open')\n        .trigger('shown.bs.dropdown', relatedTarget)\n    }\n\n    return false\n  }\n\n  Dropdown.prototype.keydown = function (e) {\n    if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return\n\n    var $this = $(this)\n\n    e.preventDefault()\n    e.stopPropagation()\n\n    if ($this.is('.disabled, :disabled')) return\n\n    var $parent  = getParent($this)\n    var isActive = $parent.hasClass('open')\n\n    if ((!isActive && e.which != 27) || (isActive && e.which == 27)) {\n      if (e.which == 27) $parent.find(toggle).trigger('focus')\n      return $this.trigger('click')\n    }\n\n    var desc = ' li:not(.divider):visible a'\n    var $items = $parent.find('[role=\"menu\"]' + desc + ', [role=\"listbox\"]' + desc)\n\n    if (!$items.length) return\n\n    var index = $items.index(e.target)\n\n    if (e.which == 38 && index > 0)                 index--                        // up\n    if (e.which == 40 && index < $items.length - 1) index++                        // down\n    if (!~index)                                      index = 0\n\n    $items.eq(index).trigger('focus')\n  }\n\n  function clearMenus(e) {\n    if (e && e.which === 3) return\n    $(backdrop).remove()\n    $(toggle).each(function () {\n      var $this         = $(this)\n      var $parent       = getParent($this)\n      var relatedTarget = { relatedTarget: this }\n\n      if (!$parent.hasClass('open')) return\n\n      $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))\n\n      if (e.isDefaultPrevented()) return\n\n      $this.attr('aria-expanded', 'false')\n      $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)\n    })\n  }\n\n  function getParent($this) {\n    var selector = $this.attr('data-target')\n\n    if (!selector) {\n      selector = $this.attr('href')\n      selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\\s]*$)/, '') // strip for ie7\n    }\n\n    var $parent = selector && $(selector)\n\n    return $parent && $parent.length ? $parent : $this.parent()\n  }\n\n\n  // DROPDOWN PLUGIN DEFINITION\n  // ==========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this = $(this)\n      var data  = $this.data('bs.dropdown')\n\n      if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))\n      if (typeof option == 'string') data[option].call($this)\n    })\n  }\n\n  var old = $.fn.dropdown\n\n  $.fn.dropdown             = Plugin\n  $.fn.dropdown.Constructor = Dropdown\n\n\n  // DROPDOWN NO CONFLICT\n  // ====================\n\n  $.fn.dropdown.noConflict = function () {\n    $.fn.dropdown = old\n    return this\n  }\n\n\n  // APPLY TO STANDARD DROPDOWN ELEMENTS\n  // ===================================\n\n  $(document)\n    .on('click.bs.dropdown.data-api', clearMenus)\n    .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })\n    .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)\n    .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)\n    .on('keydown.bs.dropdown.data-api', '[role=\"menu\"]', Dropdown.prototype.keydown)\n    .on('keydown.bs.dropdown.data-api', '[role=\"listbox\"]', Dropdown.prototype.keydown)\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: tab.js v3.3.1\n * http://getbootstrap.com/javascript/#tabs\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // TAB CLASS DEFINITION\n  // ====================\n\n  var Tab = function (element) {\n    this.element = $(element)\n  }\n\n  Tab.VERSION = '3.3.1'\n\n  Tab.TRANSITION_DURATION = 150\n\n  Tab.prototype.show = function () {\n    var $this    = this.element\n    var $ul      = $this.closest('ul:not(.dropdown-menu)')\n    var selector = $this.data('target')\n\n    if (!selector) {\n      selector = $this.attr('href')\n      selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, '') // strip for ie7\n    }\n\n    if ($this.parent('li').hasClass('active')) return\n\n    var $previous = $ul.find('.active:last a')\n    var hideEvent = $.Event('hide.bs.tab', {\n      relatedTarget: $this[0]\n    })\n    var showEvent = $.Event('show.bs.tab', {\n      relatedTarget: $previous[0]\n    })\n\n    $previous.trigger(hideEvent)\n    $this.trigger(showEvent)\n\n    if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return\n\n    var $target = $(selector)\n\n    this.activate($this.closest('li'), $ul)\n    this.activate($target, $target.parent(), function () {\n      $previous.trigger({\n        type: 'hidden.bs.tab',\n        relatedTarget: $this[0]\n      })\n      $this.trigger({\n        type: 'shown.bs.tab',\n        relatedTarget: $previous[0]\n      })\n    })\n  }\n\n  Tab.prototype.activate = function (element, container, callback) {\n    var $active    = container.find('> .active')\n    var transition = callback\n      && $.support.transition\n      && (($active.length && $active.hasClass('fade')) || !!container.find('> .fade').length)\n\n    function next() {\n      $active\n        .removeClass('active')\n        .find('> .dropdown-menu > .active')\n          .removeClass('active')\n        .end()\n        .find('[data-toggle=\"tab\"]')\n          .attr('aria-expanded', false)\n\n      element\n        .addClass('active')\n        .find('[data-toggle=\"tab\"]')\n          .attr('aria-expanded', true)\n\n      if (transition) {\n        element[0].offsetWidth // reflow for transition\n        element.addClass('in')\n      } else {\n        element.removeClass('fade')\n      }\n\n      if (element.parent('.dropdown-menu')) {\n        element\n          .closest('li.dropdown')\n            .addClass('active')\n          .end()\n          .find('[data-toggle=\"tab\"]')\n            .attr('aria-expanded', true)\n      }\n\n      callback && callback()\n    }\n\n    $active.length && transition ?\n      $active\n        .one('bsTransitionEnd', next)\n        .emulateTransitionEnd(Tab.TRANSITION_DURATION) :\n      next()\n\n    $active.removeClass('in')\n  }\n\n\n  // TAB PLUGIN DEFINITION\n  // =====================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this = $(this)\n      var data  = $this.data('bs.tab')\n\n      if (!data) $this.data('bs.tab', (data = new Tab(this)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.tab\n\n  $.fn.tab             = Plugin\n  $.fn.tab.Constructor = Tab\n\n\n  // TAB NO CONFLICT\n  // ===============\n\n  $.fn.tab.noConflict = function () {\n    $.fn.tab = old\n    return this\n  }\n\n\n  // TAB DATA-API\n  // ============\n\n  var clickHandler = function (e) {\n    e.preventDefault()\n    Plugin.call($(this), 'show')\n  }\n\n  $(document)\n    .on('click.bs.tab.data-api', '[data-toggle=\"tab\"]', clickHandler)\n    .on('click.bs.tab.data-api', '[data-toggle=\"pill\"]', clickHandler)\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: transition.js v3.3.1\n * http://getbootstrap.com/javascript/#transitions\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)\n  // ============================================================\n\n  function transitionEnd() {\n    var el = document.createElement('bootstrap')\n\n    var transEndEventNames = {\n      WebkitTransition : 'webkitTransitionEnd',\n      MozTransition    : 'transitionend',\n      OTransition      : 'oTransitionEnd otransitionend',\n      transition       : 'transitionend'\n    }\n\n    for (var name in transEndEventNames) {\n      if (el.style[name] !== undefined) {\n        return { end: transEndEventNames[name] }\n      }\n    }\n\n    return false // explicit for ie8 (  ._.)\n  }\n\n  // http://blog.alexmaccaw.com/css-transitions\n  $.fn.emulateTransitionEnd = function (duration) {\n    var called = false\n    var $el = this\n    $(this).one('bsTransitionEnd', function () { called = true })\n    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }\n    setTimeout(callback, duration)\n    return this\n  }\n\n  $(function () {\n    $.support.transition = transitionEnd()\n\n    if (!$.support.transition) return\n\n    $.event.special.bsTransitionEnd = {\n      bindType: $.support.transition.end,\n      delegateType: $.support.transition.end,\n      handle: function (e) {\n        if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)\n      }\n    }\n  })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: scrollspy.js v3.3.1\n * http://getbootstrap.com/javascript/#scrollspy\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // SCROLLSPY CLASS DEFINITION\n  // ==========================\n\n  function ScrollSpy(element, options) {\n    var process  = $.proxy(this.process, this)\n\n    this.$body          = $('body')\n    this.$scrollElement = $(element).is('body') ? $(window) : $(element)\n    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)\n    this.selector       = (this.options.target || '') + ' .nav li > a'\n    this.offsets        = []\n    this.targets        = []\n    this.activeTarget   = null\n    this.scrollHeight   = 0\n\n    this.$scrollElement.on('scroll.bs.scrollspy', process)\n    this.refresh()\n    this.process()\n  }\n\n  ScrollSpy.VERSION  = '3.3.1'\n\n  ScrollSpy.DEFAULTS = {\n    offset: 10\n  }\n\n  ScrollSpy.prototype.getScrollHeight = function () {\n    return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)\n  }\n\n  ScrollSpy.prototype.refresh = function () {\n    var offsetMethod = 'offset'\n    var offsetBase   = 0\n\n    if (!$.isWindow(this.$scrollElement[0])) {\n      offsetMethod = 'position'\n      offsetBase   = this.$scrollElement.scrollTop()\n    }\n\n    this.offsets = []\n    this.targets = []\n    this.scrollHeight = this.getScrollHeight()\n\n    var self     = this\n\n    this.$body\n      .find(this.selector)\n      .map(function () {\n        var $el   = $(this)\n        var href  = $el.data('target') || $el.attr('href')\n        var $href = /^#./.test(href) && $(href)\n\n        return ($href\n          && $href.length\n          && $href.is(':visible')\n          && [[$href[offsetMethod]().top + offsetBase, href]]) || null\n      })\n      .sort(function (a, b) { return a[0] - b[0] })\n      .each(function () {\n        self.offsets.push(this[0])\n        self.targets.push(this[1])\n      })\n  }\n\n  ScrollSpy.prototype.process = function () {\n    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset\n    var scrollHeight = this.getScrollHeight()\n    var maxScroll    = this.options.offset + scrollHeight - this.$scrollElement.height()\n    var offsets      = this.offsets\n    var targets      = this.targets\n    var activeTarget = this.activeTarget\n    var i\n\n    if (this.scrollHeight != scrollHeight) {\n      this.refresh()\n    }\n\n    if (scrollTop >= maxScroll) {\n      return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)\n    }\n\n    if (activeTarget && scrollTop < offsets[0]) {\n      this.activeTarget = null\n      return this.clear()\n    }\n\n    for (i = offsets.length; i--;) {\n      activeTarget != targets[i]\n        && scrollTop >= offsets[i]\n        && (!offsets[i + 1] || scrollTop <= offsets[i + 1])\n        && this.activate(targets[i])\n    }\n  }\n\n  ScrollSpy.prototype.activate = function (target) {\n    this.activeTarget = target\n\n    this.clear()\n\n    var selector = this.selector +\n        '[data-target=\"' + target + '\"],' +\n        this.selector + '[href=\"' + target + '\"]'\n\n    var active = $(selector)\n      .parents('li')\n      .addClass('active')\n\n    if (active.parent('.dropdown-menu').length) {\n      active = active\n        .closest('li.dropdown')\n        .addClass('active')\n    }\n\n    active.trigger('activate.bs.scrollspy')\n  }\n\n  ScrollSpy.prototype.clear = function () {\n    $(this.selector)\n      .parentsUntil(this.options.target, '.active')\n      .removeClass('active')\n  }\n\n\n  // SCROLLSPY PLUGIN DEFINITION\n  // ===========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.scrollspy')\n      var options = typeof option == 'object' && option\n\n      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.scrollspy\n\n  $.fn.scrollspy             = Plugin\n  $.fn.scrollspy.Constructor = ScrollSpy\n\n\n  // SCROLLSPY NO CONFLICT\n  // =====================\n\n  $.fn.scrollspy.noConflict = function () {\n    $.fn.scrollspy = old\n    return this\n  }\n\n\n  // SCROLLSPY DATA-API\n  // ==================\n\n  $(window).on('load.bs.scrollspy.data-api', function () {\n    $('[data-spy=\"scroll\"]').each(function () {\n      var $spy = $(this)\n      Plugin.call($spy, $spy.data())\n    })\n  })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: modal.js v3.3.1\n * http://getbootstrap.com/javascript/#modals\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // MODAL CLASS DEFINITION\n  // ======================\n\n  var Modal = function (element, options) {\n    this.options        = options\n    this.$body          = $(document.body)\n    this.$element       = $(element)\n    this.$backdrop      =\n    this.isShown        = null\n    this.scrollbarWidth = 0\n\n    if (this.options.remote) {\n      this.$element\n        .find('.modal-content')\n        .load(this.options.remote, $.proxy(function () {\n          this.$element.trigger('loaded.bs.modal')\n        }, this))\n    }\n  }\n\n  Modal.VERSION  = '3.3.1'\n\n  Modal.TRANSITION_DURATION = 300\n  Modal.BACKDROP_TRANSITION_DURATION = 150\n\n  Modal.DEFAULTS = {\n    backdrop: true,\n    keyboard: true,\n    show: true\n  }\n\n  Modal.prototype.toggle = function (_relatedTarget) {\n    return this.isShown ? this.hide() : this.show(_relatedTarget)\n  }\n\n  Modal.prototype.show = function (_relatedTarget) {\n    var that = this\n    var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })\n\n    this.$element.trigger(e)\n\n    if (this.isShown || e.isDefaultPrevented()) return\n\n    this.isShown = true\n\n    this.checkScrollbar()\n    this.setScrollbar()\n    this.$body.addClass('modal-open')\n\n    this.escape()\n    this.resize()\n\n    this.$element.on('click.dismiss.bs.modal', '[data-dismiss=\"modal\"]', $.proxy(this.hide, this))\n\n    this.backdrop(function () {\n      var transition = $.support.transition && that.$element.hasClass('fade')\n\n      if (!that.$element.parent().length) {\n        that.$element.appendTo(that.$body) // don't move modals dom position\n      }\n\n      that.$element\n        .show()\n        .scrollTop(0)\n\n      if (that.options.backdrop) that.adjustBackdrop()\n      that.adjustDialog()\n\n      if (transition) {\n        that.$element[0].offsetWidth // force reflow\n      }\n\n      that.$element\n        .addClass('in')\n        .attr('aria-hidden', false)\n\n      that.enforceFocus()\n\n      var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })\n\n      transition ?\n        that.$element.find('.modal-dialog') // wait for modal to slide in\n          .one('bsTransitionEnd', function () {\n            that.$element.trigger('focus').trigger(e)\n          })\n          .emulateTransitionEnd(Modal.TRANSITION_DURATION) :\n        that.$element.trigger('focus').trigger(e)\n    })\n  }\n\n  Modal.prototype.hide = function (e) {\n    if (e) e.preventDefault()\n\n    e = $.Event('hide.bs.modal')\n\n    this.$element.trigger(e)\n\n    if (!this.isShown || e.isDefaultPrevented()) return\n\n    this.isShown = false\n\n    this.escape()\n    this.resize()\n\n    $(document).off('focusin.bs.modal')\n\n    this.$element\n      .removeClass('in')\n      .attr('aria-hidden', true)\n      .off('click.dismiss.bs.modal')\n\n    $.support.transition && this.$element.hasClass('fade') ?\n      this.$element\n        .one('bsTransitionEnd', $.proxy(this.hideModal, this))\n        .emulateTransitionEnd(Modal.TRANSITION_DURATION) :\n      this.hideModal()\n  }\n\n  Modal.prototype.enforceFocus = function () {\n    $(document)\n      .off('focusin.bs.modal') // guard against infinite focus loop\n      .on('focusin.bs.modal', $.proxy(function (e) {\n        if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {\n          this.$element.trigger('focus')\n        }\n      }, this))\n  }\n\n  Modal.prototype.escape = function () {\n    if (this.isShown && this.options.keyboard) {\n      this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {\n        e.which == 27 && this.hide()\n      }, this))\n    } else if (!this.isShown) {\n      this.$element.off('keydown.dismiss.bs.modal')\n    }\n  }\n\n  Modal.prototype.resize = function () {\n    if (this.isShown) {\n      $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))\n    } else {\n      $(window).off('resize.bs.modal')\n    }\n  }\n\n  Modal.prototype.hideModal = function () {\n    var that = this\n    this.$element.hide()\n    this.backdrop(function () {\n      that.$body.removeClass('modal-open')\n      that.resetAdjustments()\n      that.resetScrollbar()\n      that.$element.trigger('hidden.bs.modal')\n    })\n  }\n\n  Modal.prototype.removeBackdrop = function () {\n    this.$backdrop && this.$backdrop.remove()\n    this.$backdrop = null\n  }\n\n  Modal.prototype.backdrop = function (callback) {\n    var that = this\n    var animate = this.$element.hasClass('fade') ? 'fade' : ''\n\n    if (this.isShown && this.options.backdrop) {\n      var doAnimate = $.support.transition && animate\n\n      this.$backdrop = $('<div class=\"modal-backdrop ' + animate + '\" />')\n        .prependTo(this.$element)\n        .on('click.dismiss.bs.modal', $.proxy(function (e) {\n          if (e.target !== e.currentTarget) return\n          this.options.backdrop == 'static'\n            ? this.$element[0].focus.call(this.$element[0])\n            : this.hide.call(this)\n        }, this))\n\n      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow\n\n      this.$backdrop.addClass('in')\n\n      if (!callback) return\n\n      doAnimate ?\n        this.$backdrop\n          .one('bsTransitionEnd', callback)\n          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :\n        callback()\n\n    } else if (!this.isShown && this.$backdrop) {\n      this.$backdrop.removeClass('in')\n\n      var callbackRemove = function () {\n        that.removeBackdrop()\n        callback && callback()\n      }\n      $.support.transition && this.$element.hasClass('fade') ?\n        this.$backdrop\n          .one('bsTransitionEnd', callbackRemove)\n          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :\n        callbackRemove()\n\n    } else if (callback) {\n      callback()\n    }\n  }\n\n  // these following methods are used to handle overflowing modals\n\n  Modal.prototype.handleUpdate = function () {\n    if (this.options.backdrop) this.adjustBackdrop()\n    this.adjustDialog()\n  }\n\n  Modal.prototype.adjustBackdrop = function () {\n    this.$backdrop\n      .css('height', 0)\n      .css('height', this.$element[0].scrollHeight)\n  }\n\n  Modal.prototype.adjustDialog = function () {\n    var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight\n\n    this.$element.css({\n      paddingLeft:  !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',\n      paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''\n    })\n  }\n\n  Modal.prototype.resetAdjustments = function () {\n    this.$element.css({\n      paddingLeft: '',\n      paddingRight: ''\n    })\n  }\n\n  Modal.prototype.checkScrollbar = function () {\n    this.bodyIsOverflowing = document.body.scrollHeight > document.documentElement.clientHeight\n    this.scrollbarWidth = this.measureScrollbar()\n  }\n\n  Modal.prototype.setScrollbar = function () {\n    var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)\n    if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)\n  }\n\n  Modal.prototype.resetScrollbar = function () {\n    this.$body.css('padding-right', '')\n  }\n\n  Modal.prototype.measureScrollbar = function () { // thx walsh\n    var scrollDiv = document.createElement('div')\n    scrollDiv.className = 'modal-scrollbar-measure'\n    this.$body.append(scrollDiv)\n    var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth\n    this.$body[0].removeChild(scrollDiv)\n    return scrollbarWidth\n  }\n\n\n  // MODAL PLUGIN DEFINITION\n  // =======================\n\n  function Plugin(option, _relatedTarget) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.modal')\n      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)\n\n      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))\n      if (typeof option == 'string') data[option](_relatedTarget)\n      else if (options.show) data.show(_relatedTarget)\n    })\n  }\n\n  var old = $.fn.modal\n\n  $.fn.modal             = Plugin\n  $.fn.modal.Constructor = Modal\n\n\n  // MODAL NO CONFLICT\n  // =================\n\n  $.fn.modal.noConflict = function () {\n    $.fn.modal = old\n    return this\n  }\n\n\n  // MODAL DATA-API\n  // ==============\n\n  $(document).on('click.bs.modal.data-api', '[data-toggle=\"modal\"]', function (e) {\n    var $this   = $(this)\n    var href    = $this.attr('href')\n    var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\\s]+$)/, ''))) // strip for ie7\n    var option  = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())\n\n    if ($this.is('a')) e.preventDefault()\n\n    $target.one('show.bs.modal', function (showEvent) {\n      if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown\n      $target.one('hidden.bs.modal', function () {\n        $this.is(':visible') && $this.trigger('focus')\n      })\n    })\n    Plugin.call($target, option, this)\n  })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: tooltip.js v3.3.1\n * http://getbootstrap.com/javascript/#tooltip\n * Inspired by the original jQuery.tipsy by Jason Frame\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // TOOLTIP PUBLIC CLASS DEFINITION\n  // ===============================\n\n  var Tooltip = function (element, options) {\n    this.type       =\n    this.options    =\n    this.enabled    =\n    this.timeout    =\n    this.hoverState =\n    this.$element   = null\n\n    this.init('tooltip', element, options)\n  }\n\n  Tooltip.VERSION  = '3.3.1'\n\n  Tooltip.TRANSITION_DURATION = 150\n\n  Tooltip.DEFAULTS = {\n    animation: true,\n    placement: 'top',\n    selector: false,\n    template: '<div class=\"tooltip\" role=\"tooltip\"><div class=\"tooltip-arrow\"></div><div class=\"tooltip-inner\"></div></div>',\n    trigger: 'hover focus',\n    title: '',\n    delay: 0,\n    html: false,\n    container: false,\n    viewport: {\n      selector: 'body',\n      padding: 0\n    }\n  }\n\n  Tooltip.prototype.init = function (type, element, options) {\n    this.enabled   = true\n    this.type      = type\n    this.$element  = $(element)\n    this.options   = this.getOptions(options)\n    this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)\n\n    var triggers = this.options.trigger.split(' ')\n\n    for (var i = triggers.length; i--;) {\n      var trigger = triggers[i]\n\n      if (trigger == 'click') {\n        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))\n      } else if (trigger != 'manual') {\n        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'\n        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'\n\n        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))\n        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))\n      }\n    }\n\n    this.options.selector ?\n      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :\n      this.fixTitle()\n  }\n\n  Tooltip.prototype.getDefaults = function () {\n    return Tooltip.DEFAULTS\n  }\n\n  Tooltip.prototype.getOptions = function (options) {\n    options = $.extend({}, this.getDefaults(), this.$element.data(), options)\n\n    if (options.delay && typeof options.delay == 'number') {\n      options.delay = {\n        show: options.delay,\n        hide: options.delay\n      }\n    }\n\n    return options\n  }\n\n  Tooltip.prototype.getDelegateOptions = function () {\n    var options  = {}\n    var defaults = this.getDefaults()\n\n    this._options && $.each(this._options, function (key, value) {\n      if (defaults[key] != value) options[key] = value\n    })\n\n    return options\n  }\n\n  Tooltip.prototype.enter = function (obj) {\n    var self = obj instanceof this.constructor ?\n      obj : $(obj.currentTarget).data('bs.' + this.type)\n\n    if (self && self.$tip && self.$tip.is(':visible')) {\n      self.hoverState = 'in'\n      return\n    }\n\n    if (!self) {\n      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())\n      $(obj.currentTarget).data('bs.' + this.type, self)\n    }\n\n    clearTimeout(self.timeout)\n\n    self.hoverState = 'in'\n\n    if (!self.options.delay || !self.options.delay.show) return self.show()\n\n    self.timeout = setTimeout(function () {\n      if (self.hoverState == 'in') self.show()\n    }, self.options.delay.show)\n  }\n\n  Tooltip.prototype.leave = function (obj) {\n    var self = obj instanceof this.constructor ?\n      obj : $(obj.currentTarget).data('bs.' + this.type)\n\n    if (!self) {\n      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())\n      $(obj.currentTarget).data('bs.' + this.type, self)\n    }\n\n    clearTimeout(self.timeout)\n\n    self.hoverState = 'out'\n\n    if (!self.options.delay || !self.options.delay.hide) return self.hide()\n\n    self.timeout = setTimeout(function () {\n      if (self.hoverState == 'out') self.hide()\n    }, self.options.delay.hide)\n  }\n\n  Tooltip.prototype.show = function () {\n    var e = $.Event('show.bs.' + this.type)\n\n    if (this.hasContent() && this.enabled) {\n      this.$element.trigger(e)\n\n      var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])\n      if (e.isDefaultPrevented() || !inDom) return\n      var that = this\n\n      var $tip = this.tip()\n\n      var tipId = this.getUID(this.type)\n\n      this.setContent()\n      $tip.attr('id', tipId)\n      this.$element.attr('aria-describedby', tipId)\n\n      if (this.options.animation) $tip.addClass('fade')\n\n      var placement = typeof this.options.placement == 'function' ?\n        this.options.placement.call(this, $tip[0], this.$element[0]) :\n        this.options.placement\n\n      var autoToken = /\\s?auto?\\s?/i\n      var autoPlace = autoToken.test(placement)\n      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'\n\n      $tip\n        .detach()\n        .css({ top: 0, left: 0, display: 'block' })\n        .addClass(placement)\n        .data('bs.' + this.type, this)\n\n      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)\n\n      var pos          = this.getPosition()\n      var actualWidth  = $tip[0].offsetWidth\n      var actualHeight = $tip[0].offsetHeight\n\n      if (autoPlace) {\n        var orgPlacement = placement\n        var $container   = this.options.container ? $(this.options.container) : this.$element.parent()\n        var containerDim = this.getPosition($container)\n\n        placement = placement == 'bottom' && pos.bottom + actualHeight > containerDim.bottom ? 'top'    :\n                    placement == 'top'    && pos.top    - actualHeight < containerDim.top    ? 'bottom' :\n                    placement == 'right'  && pos.right  + actualWidth  > containerDim.width  ? 'left'   :\n                    placement == 'left'   && pos.left   - actualWidth  < containerDim.left   ? 'right'  :\n                    placement\n\n        $tip\n          .removeClass(orgPlacement)\n          .addClass(placement)\n      }\n\n      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)\n\n      this.applyPlacement(calculatedOffset, placement)\n\n      var complete = function () {\n        var prevHoverState = that.hoverState\n        that.$element.trigger('shown.bs.' + that.type)\n        that.hoverState = null\n\n        if (prevHoverState == 'out') that.leave(that)\n      }\n\n      $.support.transition && this.$tip.hasClass('fade') ?\n        $tip\n          .one('bsTransitionEnd', complete)\n          .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :\n        complete()\n    }\n  }\n\n  Tooltip.prototype.applyPlacement = function (offset, placement) {\n    var $tip   = this.tip()\n    var width  = $tip[0].offsetWidth\n    var height = $tip[0].offsetHeight\n\n    // manually read margins because getBoundingClientRect includes difference\n    var marginTop = parseInt($tip.css('margin-top'), 10)\n    var marginLeft = parseInt($tip.css('margin-left'), 10)\n\n    // we must check for NaN for ie 8/9\n    if (isNaN(marginTop))  marginTop  = 0\n    if (isNaN(marginLeft)) marginLeft = 0\n\n    offset.top  = offset.top  + marginTop\n    offset.left = offset.left + marginLeft\n\n    // $.fn.offset doesn't round pixel values\n    // so we use setOffset directly with our own function B-0\n    $.offset.setOffset($tip[0], $.extend({\n      using: function (props) {\n        $tip.css({\n          top: Math.round(props.top),\n          left: Math.round(props.left)\n        })\n      }\n    }, offset), 0)\n\n    $tip.addClass('in')\n\n    // check to see if placing tip in new offset caused the tip to resize itself\n    var actualWidth  = $tip[0].offsetWidth\n    var actualHeight = $tip[0].offsetHeight\n\n    if (placement == 'top' && actualHeight != height) {\n      offset.top = offset.top + height - actualHeight\n    }\n\n    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)\n\n    if (delta.left) offset.left += delta.left\n    else offset.top += delta.top\n\n    var isVertical          = /top|bottom/.test(placement)\n    var arrowDelta          = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight\n    var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'\n\n    $tip.offset(offset)\n    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)\n  }\n\n  Tooltip.prototype.replaceArrow = function (delta, dimension, isHorizontal) {\n    this.arrow()\n      .css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')\n      .css(isHorizontal ? 'top' : 'left', '')\n  }\n\n  Tooltip.prototype.setContent = function () {\n    var $tip  = this.tip()\n    var title = this.getTitle()\n\n    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)\n    $tip.removeClass('fade in top bottom left right')\n  }\n\n  Tooltip.prototype.hide = function (callback) {\n    var that = this\n    var $tip = this.tip()\n    var e    = $.Event('hide.bs.' + this.type)\n\n    function complete() {\n      if (that.hoverState != 'in') $tip.detach()\n      that.$element\n        .removeAttr('aria-describedby')\n        .trigger('hidden.bs.' + that.type)\n      callback && callback()\n    }\n\n    this.$element.trigger(e)\n\n    if (e.isDefaultPrevented()) return\n\n    $tip.removeClass('in')\n\n    $.support.transition && this.$tip.hasClass('fade') ?\n      $tip\n        .one('bsTransitionEnd', complete)\n        .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :\n      complete()\n\n    this.hoverState = null\n\n    return this\n  }\n\n  Tooltip.prototype.fixTitle = function () {\n    var $e = this.$element\n    if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') {\n      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')\n    }\n  }\n\n  Tooltip.prototype.hasContent = function () {\n    return this.getTitle()\n  }\n\n  Tooltip.prototype.getPosition = function ($element) {\n    $element   = $element || this.$element\n\n    var el     = $element[0]\n    var isBody = el.tagName == 'BODY'\n\n    var elRect    = el.getBoundingClientRect()\n    if (elRect.width == null) {\n      // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093\n      elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })\n    }\n    var elOffset  = isBody ? { top: 0, left: 0 } : $element.offset()\n    var scroll    = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }\n    var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null\n\n    return $.extend({}, elRect, scroll, outerDims, elOffset)\n  }\n\n  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {\n    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2  } :\n           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2  } :\n           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :\n        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width   }\n\n  }\n\n  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {\n    var delta = { top: 0, left: 0 }\n    if (!this.$viewport) return delta\n\n    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0\n    var viewportDimensions = this.getPosition(this.$viewport)\n\n    if (/right|left/.test(placement)) {\n      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll\n      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight\n      if (topEdgeOffset < viewportDimensions.top) { // top overflow\n        delta.top = viewportDimensions.top - topEdgeOffset\n      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow\n        delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset\n      }\n    } else {\n      var leftEdgeOffset  = pos.left - viewportPadding\n      var rightEdgeOffset = pos.left + viewportPadding + actualWidth\n      if (leftEdgeOffset < viewportDimensions.left) { // left overflow\n        delta.left = viewportDimensions.left - leftEdgeOffset\n      } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow\n        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset\n      }\n    }\n\n    return delta\n  }\n\n  Tooltip.prototype.getTitle = function () {\n    var title\n    var $e = this.$element\n    var o  = this.options\n\n    title = $e.attr('data-original-title')\n      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)\n\n    return title\n  }\n\n  Tooltip.prototype.getUID = function (prefix) {\n    do prefix += ~~(Math.random() * 1000000)\n    while (document.getElementById(prefix))\n    return prefix\n  }\n\n  Tooltip.prototype.tip = function () {\n    return (this.$tip = this.$tip || $(this.options.template))\n  }\n\n  Tooltip.prototype.arrow = function () {\n    return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))\n  }\n\n  Tooltip.prototype.enable = function () {\n    this.enabled = true\n  }\n\n  Tooltip.prototype.disable = function () {\n    this.enabled = false\n  }\n\n  Tooltip.prototype.toggleEnabled = function () {\n    this.enabled = !this.enabled\n  }\n\n  Tooltip.prototype.toggle = function (e) {\n    var self = this\n    if (e) {\n      self = $(e.currentTarget).data('bs.' + this.type)\n      if (!self) {\n        self = new this.constructor(e.currentTarget, this.getDelegateOptions())\n        $(e.currentTarget).data('bs.' + this.type, self)\n      }\n    }\n\n    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)\n  }\n\n  Tooltip.prototype.destroy = function () {\n    var that = this\n    clearTimeout(this.timeout)\n    this.hide(function () {\n      that.$element.off('.' + that.type).removeData('bs.' + that.type)\n    })\n  }\n\n\n  // TOOLTIP PLUGIN DEFINITION\n  // =========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this    = $(this)\n      var data     = $this.data('bs.tooltip')\n      var options  = typeof option == 'object' && option\n      var selector = options && options.selector\n\n      if (!data && option == 'destroy') return\n      if (selector) {\n        if (!data) $this.data('bs.tooltip', (data = {}))\n        if (!data[selector]) data[selector] = new Tooltip(this, options)\n      } else {\n        if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))\n      }\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.tooltip\n\n  $.fn.tooltip             = Plugin\n  $.fn.tooltip.Constructor = Tooltip\n\n\n  // TOOLTIP NO CONFLICT\n  // ===================\n\n  $.fn.tooltip.noConflict = function () {\n    $.fn.tooltip = old\n    return this\n  }\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: popover.js v3.3.1\n * http://getbootstrap.com/javascript/#popovers\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // POPOVER PUBLIC CLASS DEFINITION\n  // ===============================\n\n  var Popover = function (element, options) {\n    this.init('popover', element, options)\n  }\n\n  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')\n\n  Popover.VERSION  = '3.3.1'\n\n  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {\n    placement: 'right',\n    trigger: 'click',\n    content: '',\n    template: '<div class=\"popover\" role=\"tooltip\"><div class=\"arrow\"></div><h3 class=\"popover-title\"></h3><div class=\"popover-content\"></div></div>'\n  })\n\n\n  // NOTE: POPOVER EXTENDS tooltip.js\n  // ================================\n\n  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)\n\n  Popover.prototype.constructor = Popover\n\n  Popover.prototype.getDefaults = function () {\n    return Popover.DEFAULTS\n  }\n\n  Popover.prototype.setContent = function () {\n    var $tip    = this.tip()\n    var title   = this.getTitle()\n    var content = this.getContent()\n\n    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)\n    $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events\n      this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'\n    ](content)\n\n    $tip.removeClass('fade top bottom left right in')\n\n    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do\n    // this manually by checking the contents.\n    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()\n  }\n\n  Popover.prototype.hasContent = function () {\n    return this.getTitle() || this.getContent()\n  }\n\n  Popover.prototype.getContent = function () {\n    var $e = this.$element\n    var o  = this.options\n\n    return $e.attr('data-content')\n      || (typeof o.content == 'function' ?\n            o.content.call($e[0]) :\n            o.content)\n  }\n\n  Popover.prototype.arrow = function () {\n    return (this.$arrow = this.$arrow || this.tip().find('.arrow'))\n  }\n\n  Popover.prototype.tip = function () {\n    if (!this.$tip) this.$tip = $(this.options.template)\n    return this.$tip\n  }\n\n\n  // POPOVER PLUGIN DEFINITION\n  // =========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this    = $(this)\n      var data     = $this.data('bs.popover')\n      var options  = typeof option == 'object' && option\n      var selector = options && options.selector\n\n      if (!data && option == 'destroy') return\n      if (selector) {\n        if (!data) $this.data('bs.popover', (data = {}))\n        if (!data[selector]) data[selector] = new Popover(this, options)\n      } else {\n        if (!data) $this.data('bs.popover', (data = new Popover(this, options)))\n      }\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.popover\n\n  $.fn.popover             = Plugin\n  $.fn.popover.Constructor = Popover\n\n\n  // POPOVER NO CONFLICT\n  // ===================\n\n  $.fn.popover.noConflict = function () {\n    $.fn.popover = old\n    return this\n  }\n\n}(jQuery);\n\n"
  },
  {
    "path": "webapp/static/js/vendor/handlebars-v1.3.0.js",
    "content": "/*!\n\n handlebars v1.3.0\n\nCopyright (C) 2011 by Yehuda Katz\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n@license\n*/\n/* exported Handlebars */\nvar Handlebars = (function() {\n// handlebars/safe-string.js\nvar __module4__ = (function() {\n  \"use strict\";\n  var __exports__;\n  // Build out our basic SafeString type\n  function SafeString(string) {\n    this.string = string;\n  }\n\n  SafeString.prototype.toString = function() {\n    return \"\" + this.string;\n  };\n\n  __exports__ = SafeString;\n  return __exports__;\n})();\n\n// handlebars/utils.js\nvar __module3__ = (function(__dependency1__) {\n  \"use strict\";\n  var __exports__ = {};\n  /*jshint -W004 */\n  var SafeString = __dependency1__;\n\n  var escape = {\n    \"&\": \"&amp;\",\n    \"<\": \"&lt;\",\n    \">\": \"&gt;\",\n    '\"': \"&quot;\",\n    \"'\": \"&#x27;\",\n    \"`\": \"&#x60;\"\n  };\n\n  var badChars = /[&<>\"'`]/g;\n  var possible = /[&<>\"'`]/;\n\n  function escapeChar(chr) {\n    return escape[chr] || \"&amp;\";\n  }\n\n  function extend(obj, value) {\n    for(var key in value) {\n      if(Object.prototype.hasOwnProperty.call(value, key)) {\n        obj[key] = value[key];\n      }\n    }\n  }\n\n  __exports__.extend = extend;var toString = Object.prototype.toString;\n  __exports__.toString = toString;\n  // Sourced from lodash\n  // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt\n  var isFunction = function(value) {\n    return typeof value === 'function';\n  };\n  // fallback for older versions of Chrome and Safari\n  if (isFunction(/x/)) {\n    isFunction = function(value) {\n      return typeof value === 'function' && toString.call(value) === '[object Function]';\n    };\n  }\n  var isFunction;\n  __exports__.isFunction = isFunction;\n  var isArray = Array.isArray || function(value) {\n    return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false;\n  };\n  __exports__.isArray = isArray;\n\n  function escapeExpression(string) {\n    // don't escape SafeStrings, since they're already safe\n    if (string instanceof SafeString) {\n      return string.toString();\n    } else if (!string && string !== 0) {\n      return \"\";\n    }\n\n    // Force a string conversion as this will be done by the append regardless and\n    // the regex test will do this transparently behind the scenes, causing issues if\n    // an object's to string has escaped characters in it.\n    string = \"\" + string;\n\n    if(!possible.test(string)) { return string; }\n    return string.replace(badChars, escapeChar);\n  }\n\n  __exports__.escapeExpression = escapeExpression;function isEmpty(value) {\n    if (!value && value !== 0) {\n      return true;\n    } else if (isArray(value) && value.length === 0) {\n      return true;\n    } else {\n      return false;\n    }\n  }\n\n  __exports__.isEmpty = isEmpty;\n  return __exports__;\n})(__module4__);\n\n// handlebars/exception.js\nvar __module5__ = (function() {\n  \"use strict\";\n  var __exports__;\n\n  var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];\n\n  function Exception(message, node) {\n    var line;\n    if (node && node.firstLine) {\n      line = node.firstLine;\n\n      message += ' - ' + line + ':' + node.firstColumn;\n    }\n\n    var tmp = Error.prototype.constructor.call(this, message);\n\n    // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.\n    for (var idx = 0; idx < errorProps.length; idx++) {\n      this[errorProps[idx]] = tmp[errorProps[idx]];\n    }\n\n    if (line) {\n      this.lineNumber = line;\n      this.column = node.firstColumn;\n    }\n  }\n\n  Exception.prototype = new Error();\n\n  __exports__ = Exception;\n  return __exports__;\n})();\n\n// handlebars/base.js\nvar __module2__ = (function(__dependency1__, __dependency2__) {\n  \"use strict\";\n  var __exports__ = {};\n  var Utils = __dependency1__;\n  var Exception = __dependency2__;\n\n  var VERSION = \"1.3.0\";\n  __exports__.VERSION = VERSION;var COMPILER_REVISION = 4;\n  __exports__.COMPILER_REVISION = COMPILER_REVISION;\n  var REVISION_CHANGES = {\n    1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it\n    2: '== 1.0.0-rc.3',\n    3: '== 1.0.0-rc.4',\n    4: '>= 1.0.0'\n  };\n  __exports__.REVISION_CHANGES = REVISION_CHANGES;\n  var isArray = Utils.isArray,\n      isFunction = Utils.isFunction,\n      toString = Utils.toString,\n      objectType = '[object Object]';\n\n  function HandlebarsEnvironment(helpers, partials) {\n    this.helpers = helpers || {};\n    this.partials = partials || {};\n\n    registerDefaultHelpers(this);\n  }\n\n  __exports__.HandlebarsEnvironment = HandlebarsEnvironment;HandlebarsEnvironment.prototype = {\n    constructor: HandlebarsEnvironment,\n\n    logger: logger,\n    log: log,\n\n    registerHelper: function(name, fn, inverse) {\n      if (toString.call(name) === objectType) {\n        if (inverse || fn) { throw new Exception('Arg not supported with multiple helpers'); }\n        Utils.extend(this.helpers, name);\n      } else {\n        if (inverse) { fn.not = inverse; }\n        this.helpers[name] = fn;\n      }\n    },\n\n    registerPartial: function(name, str) {\n      if (toString.call(name) === objectType) {\n        Utils.extend(this.partials,  name);\n      } else {\n        this.partials[name] = str;\n      }\n    }\n  };\n\n  function registerDefaultHelpers(instance) {\n    instance.registerHelper('helperMissing', function(arg) {\n      if(arguments.length === 2) {\n        return undefined;\n      } else {\n        throw new Exception(\"Missing helper: '\" + arg + \"'\");\n      }\n    });\n\n    instance.registerHelper('blockHelperMissing', function(context, options) {\n      var inverse = options.inverse || function() {}, fn = options.fn;\n\n      if (isFunction(context)) { context = context.call(this); }\n\n      if(context === true) {\n        return fn(this);\n      } else if(context === false || context == null) {\n        return inverse(this);\n      } else if (isArray(context)) {\n        if(context.length > 0) {\n          return instance.helpers.each(context, options);\n        } else {\n          return inverse(this);\n        }\n      } else {\n        return fn(context);\n      }\n    });\n\n    instance.registerHelper('each', function(context, options) {\n      var fn = options.fn, inverse = options.inverse;\n      var i = 0, ret = \"\", data;\n\n      if (isFunction(context)) { context = context.call(this); }\n\n      if (options.data) {\n        data = createFrame(options.data);\n      }\n\n      if(context && typeof context === 'object') {\n        if (isArray(context)) {\n          for(var j = context.length; i<j; i++) {\n            if (data) {\n              data.index = i;\n              data.first = (i === 0);\n              data.last  = (i === (context.length-1));\n            }\n            ret = ret + fn(context[i], { data: data });\n          }\n        } else {\n          for(var key in context) {\n            if(context.hasOwnProperty(key)) {\n              if(data) { \n                data.key = key; \n                data.index = i;\n                data.first = (i === 0);\n              }\n              ret = ret + fn(context[key], {data: data});\n              i++;\n            }\n          }\n        }\n      }\n\n      if(i === 0){\n        ret = inverse(this);\n      }\n\n      return ret;\n    });\n\n    instance.registerHelper('if', function(conditional, options) {\n      if (isFunction(conditional)) { conditional = conditional.call(this); }\n\n      // Default behavior is to render the positive path if the value is truthy and not empty.\n      // The `includeZero` option may be set to treat the condtional as purely not empty based on the\n      // behavior of isEmpty. Effectively this determines if 0 is handled by the positive path or negative.\n      if ((!options.hash.includeZero && !conditional) || Utils.isEmpty(conditional)) {\n        return options.inverse(this);\n      } else {\n        return options.fn(this);\n      }\n    });\n\n    instance.registerHelper('unless', function(conditional, options) {\n      return instance.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn, hash: options.hash});\n    });\n\n    instance.registerHelper('with', function(context, options) {\n      if (isFunction(context)) { context = context.call(this); }\n\n      if (!Utils.isEmpty(context)) return options.fn(context);\n    });\n\n    instance.registerHelper('log', function(context, options) {\n      var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1;\n      instance.log(level, context);\n    });\n  }\n\n  var logger = {\n    methodMap: { 0: 'debug', 1: 'info', 2: 'warn', 3: 'error' },\n\n    // State enum\n    DEBUG: 0,\n    INFO: 1,\n    WARN: 2,\n    ERROR: 3,\n    level: 3,\n\n    // can be overridden in the host environment\n    log: function(level, obj) {\n      if (logger.level <= level) {\n        var method = logger.methodMap[level];\n        if (typeof console !== 'undefined' && console[method]) {\n          console[method].call(console, obj);\n        }\n      }\n    }\n  };\n  __exports__.logger = logger;\n  function log(level, obj) { logger.log(level, obj); }\n\n  __exports__.log = log;var createFrame = function(object) {\n    var obj = {};\n    Utils.extend(obj, object);\n    return obj;\n  };\n  __exports__.createFrame = createFrame;\n  return __exports__;\n})(__module3__, __module5__);\n\n// handlebars/runtime.js\nvar __module6__ = (function(__dependency1__, __dependency2__, __dependency3__) {\n  \"use strict\";\n  var __exports__ = {};\n  var Utils = __dependency1__;\n  var Exception = __dependency2__;\n  var COMPILER_REVISION = __dependency3__.COMPILER_REVISION;\n  var REVISION_CHANGES = __dependency3__.REVISION_CHANGES;\n\n  function checkRevision(compilerInfo) {\n    var compilerRevision = compilerInfo && compilerInfo[0] || 1,\n        currentRevision = COMPILER_REVISION;\n\n    if (compilerRevision !== currentRevision) {\n      if (compilerRevision < currentRevision) {\n        var runtimeVersions = REVISION_CHANGES[currentRevision],\n            compilerVersions = REVISION_CHANGES[compilerRevision];\n        throw new Exception(\"Template was precompiled with an older version of Handlebars than the current runtime. \"+\n              \"Please update your precompiler to a newer version (\"+runtimeVersions+\") or downgrade your runtime to an older version (\"+compilerVersions+\").\");\n      } else {\n        // Use the embedded version info since the runtime doesn't know about this revision yet\n        throw new Exception(\"Template was precompiled with a newer version of Handlebars than the current runtime. \"+\n              \"Please update your runtime to a newer version (\"+compilerInfo[1]+\").\");\n      }\n    }\n  }\n\n  __exports__.checkRevision = checkRevision;// TODO: Remove this line and break up compilePartial\n\n  function template(templateSpec, env) {\n    if (!env) {\n      throw new Exception(\"No environment passed to template\");\n    }\n\n    // Note: Using env.VM references rather than local var references throughout this section to allow\n    // for external users to override these as psuedo-supported APIs.\n    var invokePartialWrapper = function(partial, name, context, helpers, partials, data) {\n      var result = env.VM.invokePartial.apply(this, arguments);\n      if (result != null) { return result; }\n\n      if (env.compile) {\n        var options = { helpers: helpers, partials: partials, data: data };\n        partials[name] = env.compile(partial, { data: data !== undefined }, env);\n        return partials[name](context, options);\n      } else {\n        throw new Exception(\"The partial \" + name + \" could not be compiled when running in runtime-only mode\");\n      }\n    };\n\n    // Just add water\n    var container = {\n      escapeExpression: Utils.escapeExpression,\n      invokePartial: invokePartialWrapper,\n      programs: [],\n      program: function(i, fn, data) {\n        var programWrapper = this.programs[i];\n        if(data) {\n          programWrapper = program(i, fn, data);\n        } else if (!programWrapper) {\n          programWrapper = this.programs[i] = program(i, fn);\n        }\n        return programWrapper;\n      },\n      merge: function(param, common) {\n        var ret = param || common;\n\n        if (param && common && (param !== common)) {\n          ret = {};\n          Utils.extend(ret, common);\n          Utils.extend(ret, param);\n        }\n        return ret;\n      },\n      programWithDepth: env.VM.programWithDepth,\n      noop: env.VM.noop,\n      compilerInfo: null\n    };\n\n    return function(context, options) {\n      options = options || {};\n      var namespace = options.partial ? options : env,\n          helpers,\n          partials;\n\n      if (!options.partial) {\n        helpers = options.helpers;\n        partials = options.partials;\n      }\n      var result = templateSpec.call(\n            container,\n            namespace, context,\n            helpers,\n            partials,\n            options.data);\n\n      if (!options.partial) {\n        env.VM.checkRevision(container.compilerInfo);\n      }\n\n      return result;\n    };\n  }\n\n  __exports__.template = template;function programWithDepth(i, fn, data /*, $depth */) {\n    var args = Array.prototype.slice.call(arguments, 3);\n\n    var prog = function(context, options) {\n      options = options || {};\n\n      return fn.apply(this, [context, options.data || data].concat(args));\n    };\n    prog.program = i;\n    prog.depth = args.length;\n    return prog;\n  }\n\n  __exports__.programWithDepth = programWithDepth;function program(i, fn, data) {\n    var prog = function(context, options) {\n      options = options || {};\n\n      return fn(context, options.data || data);\n    };\n    prog.program = i;\n    prog.depth = 0;\n    return prog;\n  }\n\n  __exports__.program = program;function invokePartial(partial, name, context, helpers, partials, data) {\n    var options = { partial: true, helpers: helpers, partials: partials, data: data };\n\n    if(partial === undefined) {\n      throw new Exception(\"The partial \" + name + \" could not be found\");\n    } else if(partial instanceof Function) {\n      return partial(context, options);\n    }\n  }\n\n  __exports__.invokePartial = invokePartial;function noop() { return \"\"; }\n\n  __exports__.noop = noop;\n  return __exports__;\n})(__module3__, __module5__, __module2__);\n\n// handlebars.runtime.js\nvar __module1__ = (function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__) {\n  \"use strict\";\n  var __exports__;\n  /*globals Handlebars: true */\n  var base = __dependency1__;\n\n  // Each of these augment the Handlebars object. No need to setup here.\n  // (This is done to easily share code between commonjs and browse envs)\n  var SafeString = __dependency2__;\n  var Exception = __dependency3__;\n  var Utils = __dependency4__;\n  var runtime = __dependency5__;\n\n  // For compatibility and usage outside of module systems, make the Handlebars object a namespace\n  var create = function() {\n    var hb = new base.HandlebarsEnvironment();\n\n    Utils.extend(hb, base);\n    hb.SafeString = SafeString;\n    hb.Exception = Exception;\n    hb.Utils = Utils;\n\n    hb.VM = runtime;\n    hb.template = function(spec) {\n      return runtime.template(spec, hb);\n    };\n\n    return hb;\n  };\n\n  var Handlebars = create();\n  Handlebars.create = create;\n\n  __exports__ = Handlebars;\n  return __exports__;\n})(__module2__, __module4__, __module5__, __module3__, __module6__);\n\n// handlebars/compiler/ast.js\nvar __module7__ = (function(__dependency1__) {\n  \"use strict\";\n  var __exports__;\n  var Exception = __dependency1__;\n\n  function LocationInfo(locInfo){\n    locInfo = locInfo || {};\n    this.firstLine   = locInfo.first_line;\n    this.firstColumn = locInfo.first_column;\n    this.lastColumn  = locInfo.last_column;\n    this.lastLine    = locInfo.last_line;\n  }\n\n  var AST = {\n    ProgramNode: function(statements, inverseStrip, inverse, locInfo) {\n      var inverseLocationInfo, firstInverseNode;\n      if (arguments.length === 3) {\n        locInfo = inverse;\n        inverse = null;\n      } else if (arguments.length === 2) {\n        locInfo = inverseStrip;\n        inverseStrip = null;\n      }\n\n      LocationInfo.call(this, locInfo);\n      this.type = \"program\";\n      this.statements = statements;\n      this.strip = {};\n\n      if(inverse) {\n        firstInverseNode = inverse[0];\n        if (firstInverseNode) {\n          inverseLocationInfo = {\n            first_line: firstInverseNode.firstLine,\n            last_line: firstInverseNode.lastLine,\n            last_column: firstInverseNode.lastColumn,\n            first_column: firstInverseNode.firstColumn\n          };\n          this.inverse = new AST.ProgramNode(inverse, inverseStrip, inverseLocationInfo);\n        } else {\n          this.inverse = new AST.ProgramNode(inverse, inverseStrip);\n        }\n        this.strip.right = inverseStrip.left;\n      } else if (inverseStrip) {\n        this.strip.left = inverseStrip.right;\n      }\n    },\n\n    MustacheNode: function(rawParams, hash, open, strip, locInfo) {\n      LocationInfo.call(this, locInfo);\n      this.type = \"mustache\";\n      this.strip = strip;\n\n      // Open may be a string parsed from the parser or a passed boolean flag\n      if (open != null && open.charAt) {\n        // Must use charAt to support IE pre-10\n        var escapeFlag = open.charAt(3) || open.charAt(2);\n        this.escaped = escapeFlag !== '{' && escapeFlag !== '&';\n      } else {\n        this.escaped = !!open;\n      }\n\n      if (rawParams instanceof AST.SexprNode) {\n        this.sexpr = rawParams;\n      } else {\n        // Support old AST API\n        this.sexpr = new AST.SexprNode(rawParams, hash);\n      }\n\n      this.sexpr.isRoot = true;\n\n      // Support old AST API that stored this info in MustacheNode\n      this.id = this.sexpr.id;\n      this.params = this.sexpr.params;\n      this.hash = this.sexpr.hash;\n      this.eligibleHelper = this.sexpr.eligibleHelper;\n      this.isHelper = this.sexpr.isHelper;\n    },\n\n    SexprNode: function(rawParams, hash, locInfo) {\n      LocationInfo.call(this, locInfo);\n\n      this.type = \"sexpr\";\n      this.hash = hash;\n\n      var id = this.id = rawParams[0];\n      var params = this.params = rawParams.slice(1);\n\n      // a mustache is an eligible helper if:\n      // * its id is simple (a single part, not `this` or `..`)\n      var eligibleHelper = this.eligibleHelper = id.isSimple;\n\n      // a mustache is definitely a helper if:\n      // * it is an eligible helper, and\n      // * it has at least one parameter or hash segment\n      this.isHelper = eligibleHelper && (params.length || hash);\n\n      // if a mustache is an eligible helper but not a definite\n      // helper, it is ambiguous, and will be resolved in a later\n      // pass or at runtime.\n    },\n\n    PartialNode: function(partialName, context, strip, locInfo) {\n      LocationInfo.call(this, locInfo);\n      this.type         = \"partial\";\n      this.partialName  = partialName;\n      this.context      = context;\n      this.strip = strip;\n    },\n\n    BlockNode: function(mustache, program, inverse, close, locInfo) {\n      LocationInfo.call(this, locInfo);\n\n      if(mustache.sexpr.id.original !== close.path.original) {\n        throw new Exception(mustache.sexpr.id.original + \" doesn't match \" + close.path.original, this);\n      }\n\n      this.type = 'block';\n      this.mustache = mustache;\n      this.program  = program;\n      this.inverse  = inverse;\n\n      this.strip = {\n        left: mustache.strip.left,\n        right: close.strip.right\n      };\n\n      (program || inverse).strip.left = mustache.strip.right;\n      (inverse || program).strip.right = close.strip.left;\n\n      if (inverse && !program) {\n        this.isInverse = true;\n      }\n    },\n\n    ContentNode: function(string, locInfo) {\n      LocationInfo.call(this, locInfo);\n      this.type = \"content\";\n      this.string = string;\n    },\n\n    HashNode: function(pairs, locInfo) {\n      LocationInfo.call(this, locInfo);\n      this.type = \"hash\";\n      this.pairs = pairs;\n    },\n\n    IdNode: function(parts, locInfo) {\n      LocationInfo.call(this, locInfo);\n      this.type = \"ID\";\n\n      var original = \"\",\n          dig = [],\n          depth = 0;\n\n      for(var i=0,l=parts.length; i<l; i++) {\n        var part = parts[i].part;\n        original += (parts[i].separator || '') + part;\n\n        if (part === \"..\" || part === \".\" || part === \"this\") {\n          if (dig.length > 0) {\n            throw new Exception(\"Invalid path: \" + original, this);\n          } else if (part === \"..\") {\n            depth++;\n          } else {\n            this.isScoped = true;\n          }\n        } else {\n          dig.push(part);\n        }\n      }\n\n      this.original = original;\n      this.parts    = dig;\n      this.string   = dig.join('.');\n      this.depth    = depth;\n\n      // an ID is simple if it only has one part, and that part is not\n      // `..` or `this`.\n      this.isSimple = parts.length === 1 && !this.isScoped && depth === 0;\n\n      this.stringModeValue = this.string;\n    },\n\n    PartialNameNode: function(name, locInfo) {\n      LocationInfo.call(this, locInfo);\n      this.type = \"PARTIAL_NAME\";\n      this.name = name.original;\n    },\n\n    DataNode: function(id, locInfo) {\n      LocationInfo.call(this, locInfo);\n      this.type = \"DATA\";\n      this.id = id;\n    },\n\n    StringNode: function(string, locInfo) {\n      LocationInfo.call(this, locInfo);\n      this.type = \"STRING\";\n      this.original =\n        this.string =\n        this.stringModeValue = string;\n    },\n\n    IntegerNode: function(integer, locInfo) {\n      LocationInfo.call(this, locInfo);\n      this.type = \"INTEGER\";\n      this.original =\n        this.integer = integer;\n      this.stringModeValue = Number(integer);\n    },\n\n    BooleanNode: function(bool, locInfo) {\n      LocationInfo.call(this, locInfo);\n      this.type = \"BOOLEAN\";\n      this.bool = bool;\n      this.stringModeValue = bool === \"true\";\n    },\n\n    CommentNode: function(comment, locInfo) {\n      LocationInfo.call(this, locInfo);\n      this.type = \"comment\";\n      this.comment = comment;\n    }\n  };\n\n  // Must be exported as an object rather than the root of the module as the jison lexer\n  // most modify the object to operate properly.\n  __exports__ = AST;\n  return __exports__;\n})(__module5__);\n\n// handlebars/compiler/parser.js\nvar __module9__ = (function() {\n  \"use strict\";\n  var __exports__;\n  /* jshint ignore:start */\n  /* Jison generated parser */\n  var handlebars = (function(){\n  var parser = {trace: function trace() { },\n  yy: {},\n  symbols_: {\"error\":2,\"root\":3,\"statements\":4,\"EOF\":5,\"program\":6,\"simpleInverse\":7,\"statement\":8,\"openInverse\":9,\"closeBlock\":10,\"openBlock\":11,\"mustache\":12,\"partial\":13,\"CONTENT\":14,\"COMMENT\":15,\"OPEN_BLOCK\":16,\"sexpr\":17,\"CLOSE\":18,\"OPEN_INVERSE\":19,\"OPEN_ENDBLOCK\":20,\"path\":21,\"OPEN\":22,\"OPEN_UNESCAPED\":23,\"CLOSE_UNESCAPED\":24,\"OPEN_PARTIAL\":25,\"partialName\":26,\"partial_option0\":27,\"sexpr_repetition0\":28,\"sexpr_option0\":29,\"dataName\":30,\"param\":31,\"STRING\":32,\"INTEGER\":33,\"BOOLEAN\":34,\"OPEN_SEXPR\":35,\"CLOSE_SEXPR\":36,\"hash\":37,\"hash_repetition_plus0\":38,\"hashSegment\":39,\"ID\":40,\"EQUALS\":41,\"DATA\":42,\"pathSegments\":43,\"SEP\":44,\"$accept\":0,\"$end\":1},\n  terminals_: {2:\"error\",5:\"EOF\",14:\"CONTENT\",15:\"COMMENT\",16:\"OPEN_BLOCK\",18:\"CLOSE\",19:\"OPEN_INVERSE\",20:\"OPEN_ENDBLOCK\",22:\"OPEN\",23:\"OPEN_UNESCAPED\",24:\"CLOSE_UNESCAPED\",25:\"OPEN_PARTIAL\",32:\"STRING\",33:\"INTEGER\",34:\"BOOLEAN\",35:\"OPEN_SEXPR\",36:\"CLOSE_SEXPR\",40:\"ID\",41:\"EQUALS\",42:\"DATA\",44:\"SEP\"},\n  productions_: [0,[3,2],[3,1],[6,2],[6,3],[6,2],[6,1],[6,1],[6,0],[4,1],[4,2],[8,3],[8,3],[8,1],[8,1],[8,1],[8,1],[11,3],[9,3],[10,3],[12,3],[12,3],[13,4],[7,2],[17,3],[17,1],[31,1],[31,1],[31,1],[31,1],[31,1],[31,3],[37,1],[39,3],[26,1],[26,1],[26,1],[30,2],[21,1],[43,3],[43,1],[27,0],[27,1],[28,0],[28,2],[29,0],[29,1],[38,1],[38,2]],\n  performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) {\n\n  var $0 = $$.length - 1;\n  switch (yystate) {\n  case 1: return new yy.ProgramNode($$[$0-1], this._$); \n  break;\n  case 2: return new yy.ProgramNode([], this._$); \n  break;\n  case 3:this.$ = new yy.ProgramNode([], $$[$0-1], $$[$0], this._$);\n  break;\n  case 4:this.$ = new yy.ProgramNode($$[$0-2], $$[$0-1], $$[$0], this._$);\n  break;\n  case 5:this.$ = new yy.ProgramNode($$[$0-1], $$[$0], [], this._$);\n  break;\n  case 6:this.$ = new yy.ProgramNode($$[$0], this._$);\n  break;\n  case 7:this.$ = new yy.ProgramNode([], this._$);\n  break;\n  case 8:this.$ = new yy.ProgramNode([], this._$);\n  break;\n  case 9:this.$ = [$$[$0]];\n  break;\n  case 10: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]; \n  break;\n  case 11:this.$ = new yy.BlockNode($$[$0-2], $$[$0-1].inverse, $$[$0-1], $$[$0], this._$);\n  break;\n  case 12:this.$ = new yy.BlockNode($$[$0-2], $$[$0-1], $$[$0-1].inverse, $$[$0], this._$);\n  break;\n  case 13:this.$ = $$[$0];\n  break;\n  case 14:this.$ = $$[$0];\n  break;\n  case 15:this.$ = new yy.ContentNode($$[$0], this._$);\n  break;\n  case 16:this.$ = new yy.CommentNode($$[$0], this._$);\n  break;\n  case 17:this.$ = new yy.MustacheNode($$[$0-1], null, $$[$0-2], stripFlags($$[$0-2], $$[$0]), this._$);\n  break;\n  case 18:this.$ = new yy.MustacheNode($$[$0-1], null, $$[$0-2], stripFlags($$[$0-2], $$[$0]), this._$);\n  break;\n  case 19:this.$ = {path: $$[$0-1], strip: stripFlags($$[$0-2], $$[$0])};\n  break;\n  case 20:this.$ = new yy.MustacheNode($$[$0-1], null, $$[$0-2], stripFlags($$[$0-2], $$[$0]), this._$);\n  break;\n  case 21:this.$ = new yy.MustacheNode($$[$0-1], null, $$[$0-2], stripFlags($$[$0-2], $$[$0]), this._$);\n  break;\n  case 22:this.$ = new yy.PartialNode($$[$0-2], $$[$0-1], stripFlags($$[$0-3], $$[$0]), this._$);\n  break;\n  case 23:this.$ = stripFlags($$[$0-1], $$[$0]);\n  break;\n  case 24:this.$ = new yy.SexprNode([$$[$0-2]].concat($$[$0-1]), $$[$0], this._$);\n  break;\n  case 25:this.$ = new yy.SexprNode([$$[$0]], null, this._$);\n  break;\n  case 26:this.$ = $$[$0];\n  break;\n  case 27:this.$ = new yy.StringNode($$[$0], this._$);\n  break;\n  case 28:this.$ = new yy.IntegerNode($$[$0], this._$);\n  break;\n  case 29:this.$ = new yy.BooleanNode($$[$0], this._$);\n  break;\n  case 30:this.$ = $$[$0];\n  break;\n  case 31:$$[$0-1].isHelper = true; this.$ = $$[$0-1];\n  break;\n  case 32:this.$ = new yy.HashNode($$[$0], this._$);\n  break;\n  case 33:this.$ = [$$[$0-2], $$[$0]];\n  break;\n  case 34:this.$ = new yy.PartialNameNode($$[$0], this._$);\n  break;\n  case 35:this.$ = new yy.PartialNameNode(new yy.StringNode($$[$0], this._$), this._$);\n  break;\n  case 36:this.$ = new yy.PartialNameNode(new yy.IntegerNode($$[$0], this._$));\n  break;\n  case 37:this.$ = new yy.DataNode($$[$0], this._$);\n  break;\n  case 38:this.$ = new yy.IdNode($$[$0], this._$);\n  break;\n  case 39: $$[$0-2].push({part: $$[$0], separator: $$[$0-1]}); this.$ = $$[$0-2]; \n  break;\n  case 40:this.$ = [{part: $$[$0]}];\n  break;\n  case 43:this.$ = [];\n  break;\n  case 44:$$[$0-1].push($$[$0]);\n  break;\n  case 47:this.$ = [$$[$0]];\n  break;\n  case 48:$$[$0-1].push($$[$0]);\n  break;\n  }\n  },\n  table: [{3:1,4:2,5:[1,3],8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],22:[1,13],23:[1,14],25:[1,15]},{1:[3]},{5:[1,16],8:17,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],22:[1,13],23:[1,14],25:[1,15]},{1:[2,2]},{5:[2,9],14:[2,9],15:[2,9],16:[2,9],19:[2,9],20:[2,9],22:[2,9],23:[2,9],25:[2,9]},{4:20,6:18,7:19,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,21],20:[2,8],22:[1,13],23:[1,14],25:[1,15]},{4:20,6:22,7:19,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,21],20:[2,8],22:[1,13],23:[1,14],25:[1,15]},{5:[2,13],14:[2,13],15:[2,13],16:[2,13],19:[2,13],20:[2,13],22:[2,13],23:[2,13],25:[2,13]},{5:[2,14],14:[2,14],15:[2,14],16:[2,14],19:[2,14],20:[2,14],22:[2,14],23:[2,14],25:[2,14]},{5:[2,15],14:[2,15],15:[2,15],16:[2,15],19:[2,15],20:[2,15],22:[2,15],23:[2,15],25:[2,15]},{5:[2,16],14:[2,16],15:[2,16],16:[2,16],19:[2,16],20:[2,16],22:[2,16],23:[2,16],25:[2,16]},{17:23,21:24,30:25,40:[1,28],42:[1,27],43:26},{17:29,21:24,30:25,40:[1,28],42:[1,27],43:26},{17:30,21:24,30:25,40:[1,28],42:[1,27],43:26},{17:31,21:24,30:25,40:[1,28],42:[1,27],43:26},{21:33,26:32,32:[1,34],33:[1,35],40:[1,28],43:26},{1:[2,1]},{5:[2,10],14:[2,10],15:[2,10],16:[2,10],19:[2,10],20:[2,10],22:[2,10],23:[2,10],25:[2,10]},{10:36,20:[1,37]},{4:38,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,7],22:[1,13],23:[1,14],25:[1,15]},{7:39,8:17,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,21],20:[2,6],22:[1,13],23:[1,14],25:[1,15]},{17:23,18:[1,40],21:24,30:25,40:[1,28],42:[1,27],43:26},{10:41,20:[1,37]},{18:[1,42]},{18:[2,43],24:[2,43],28:43,32:[2,43],33:[2,43],34:[2,43],35:[2,43],36:[2,43],40:[2,43],42:[2,43]},{18:[2,25],24:[2,25],36:[2,25]},{18:[2,38],24:[2,38],32:[2,38],33:[2,38],34:[2,38],35:[2,38],36:[2,38],40:[2,38],42:[2,38],44:[1,44]},{21:45,40:[1,28],43:26},{18:[2,40],24:[2,40],32:[2,40],33:[2,40],34:[2,40],35:[2,40],36:[2,40],40:[2,40],42:[2,40],44:[2,40]},{18:[1,46]},{18:[1,47]},{24:[1,48]},{18:[2,41],21:50,27:49,40:[1,28],43:26},{18:[2,34],40:[2,34]},{18:[2,35],40:[2,35]},{18:[2,36],40:[2,36]},{5:[2,11],14:[2,11],15:[2,11],16:[2,11],19:[2,11],20:[2,11],22:[2,11],23:[2,11],25:[2,11]},{21:51,40:[1,28],43:26},{8:17,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,3],22:[1,13],23:[1,14],25:[1,15]},{4:52,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,5],22:[1,13],23:[1,14],25:[1,15]},{14:[2,23],15:[2,23],16:[2,23],19:[2,23],20:[2,23],22:[2,23],23:[2,23],25:[2,23]},{5:[2,12],14:[2,12],15:[2,12],16:[2,12],19:[2,12],20:[2,12],22:[2,12],23:[2,12],25:[2,12]},{14:[2,18],15:[2,18],16:[2,18],19:[2,18],20:[2,18],22:[2,18],23:[2,18],25:[2,18]},{18:[2,45],21:56,24:[2,45],29:53,30:60,31:54,32:[1,57],33:[1,58],34:[1,59],35:[1,61],36:[2,45],37:55,38:62,39:63,40:[1,64],42:[1,27],43:26},{40:[1,65]},{18:[2,37],24:[2,37],32:[2,37],33:[2,37],34:[2,37],35:[2,37],36:[2,37],40:[2,37],42:[2,37]},{14:[2,17],15:[2,17],16:[2,17],19:[2,17],20:[2,17],22:[2,17],23:[2,17],25:[2,17]},{5:[2,20],14:[2,20],15:[2,20],16:[2,20],19:[2,20],20:[2,20],22:[2,20],23:[2,20],25:[2,20]},{5:[2,21],14:[2,21],15:[2,21],16:[2,21],19:[2,21],20:[2,21],22:[2,21],23:[2,21],25:[2,21]},{18:[1,66]},{18:[2,42]},{18:[1,67]},{8:17,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,4],22:[1,13],23:[1,14],25:[1,15]},{18:[2,24],24:[2,24],36:[2,24]},{18:[2,44],24:[2,44],32:[2,44],33:[2,44],34:[2,44],35:[2,44],36:[2,44],40:[2,44],42:[2,44]},{18:[2,46],24:[2,46],36:[2,46]},{18:[2,26],24:[2,26],32:[2,26],33:[2,26],34:[2,26],35:[2,26],36:[2,26],40:[2,26],42:[2,26]},{18:[2,27],24:[2,27],32:[2,27],33:[2,27],34:[2,27],35:[2,27],36:[2,27],40:[2,27],42:[2,27]},{18:[2,28],24:[2,28],32:[2,28],33:[2,28],34:[2,28],35:[2,28],36:[2,28],40:[2,28],42:[2,28]},{18:[2,29],24:[2,29],32:[2,29],33:[2,29],34:[2,29],35:[2,29],36:[2,29],40:[2,29],42:[2,29]},{18:[2,30],24:[2,30],32:[2,30],33:[2,30],34:[2,30],35:[2,30],36:[2,30],40:[2,30],42:[2,30]},{17:68,21:24,30:25,40:[1,28],42:[1,27],43:26},{18:[2,32],24:[2,32],36:[2,32],39:69,40:[1,70]},{18:[2,47],24:[2,47],36:[2,47],40:[2,47]},{18:[2,40],24:[2,40],32:[2,40],33:[2,40],34:[2,40],35:[2,40],36:[2,40],40:[2,40],41:[1,71],42:[2,40],44:[2,40]},{18:[2,39],24:[2,39],32:[2,39],33:[2,39],34:[2,39],35:[2,39],36:[2,39],40:[2,39],42:[2,39],44:[2,39]},{5:[2,22],14:[2,22],15:[2,22],16:[2,22],19:[2,22],20:[2,22],22:[2,22],23:[2,22],25:[2,22]},{5:[2,19],14:[2,19],15:[2,19],16:[2,19],19:[2,19],20:[2,19],22:[2,19],23:[2,19],25:[2,19]},{36:[1,72]},{18:[2,48],24:[2,48],36:[2,48],40:[2,48]},{41:[1,71]},{21:56,30:60,31:73,32:[1,57],33:[1,58],34:[1,59],35:[1,61],40:[1,28],42:[1,27],43:26},{18:[2,31],24:[2,31],32:[2,31],33:[2,31],34:[2,31],35:[2,31],36:[2,31],40:[2,31],42:[2,31]},{18:[2,33],24:[2,33],36:[2,33],40:[2,33]}],\n  defaultActions: {3:[2,2],16:[2,1],50:[2,42]},\n  parseError: function parseError(str, hash) {\n      throw new Error(str);\n  },\n  parse: function parse(input) {\n      var self = this, stack = [0], vstack = [null], lstack = [], table = this.table, yytext = \"\", yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;\n      this.lexer.setInput(input);\n      this.lexer.yy = this.yy;\n      this.yy.lexer = this.lexer;\n      this.yy.parser = this;\n      if (typeof this.lexer.yylloc == \"undefined\")\n          this.lexer.yylloc = {};\n      var yyloc = this.lexer.yylloc;\n      lstack.push(yyloc);\n      var ranges = this.lexer.options && this.lexer.options.ranges;\n      if (typeof this.yy.parseError === \"function\")\n          this.parseError = this.yy.parseError;\n      function popStack(n) {\n          stack.length = stack.length - 2 * n;\n          vstack.length = vstack.length - n;\n          lstack.length = lstack.length - n;\n      }\n      function lex() {\n          var token;\n          token = self.lexer.lex() || 1;\n          if (typeof token !== \"number\") {\n              token = self.symbols_[token] || token;\n          }\n          return token;\n      }\n      var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;\n      while (true) {\n          state = stack[stack.length - 1];\n          if (this.defaultActions[state]) {\n              action = this.defaultActions[state];\n          } else {\n              if (symbol === null || typeof symbol == \"undefined\") {\n                  symbol = lex();\n              }\n              action = table[state] && table[state][symbol];\n          }\n          if (typeof action === \"undefined\" || !action.length || !action[0]) {\n              var errStr = \"\";\n              if (!recovering) {\n                  expected = [];\n                  for (p in table[state])\n                      if (this.terminals_[p] && p > 2) {\n                          expected.push(\"'\" + this.terminals_[p] + \"'\");\n                      }\n                  if (this.lexer.showPosition) {\n                      errStr = \"Parse error on line \" + (yylineno + 1) + \":\\n\" + this.lexer.showPosition() + \"\\nExpecting \" + expected.join(\", \") + \", got '\" + (this.terminals_[symbol] || symbol) + \"'\";\n                  } else {\n                      errStr = \"Parse error on line \" + (yylineno + 1) + \": Unexpected \" + (symbol == 1?\"end of input\":\"'\" + (this.terminals_[symbol] || symbol) + \"'\");\n                  }\n                  this.parseError(errStr, {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected});\n              }\n          }\n          if (action[0] instanceof Array && action.length > 1) {\n              throw new Error(\"Parse Error: multiple actions possible at state: \" + state + \", token: \" + symbol);\n          }\n          switch (action[0]) {\n          case 1:\n              stack.push(symbol);\n              vstack.push(this.lexer.yytext);\n              lstack.push(this.lexer.yylloc);\n              stack.push(action[1]);\n              symbol = null;\n              if (!preErrorSymbol) {\n                  yyleng = this.lexer.yyleng;\n                  yytext = this.lexer.yytext;\n                  yylineno = this.lexer.yylineno;\n                  yyloc = this.lexer.yylloc;\n                  if (recovering > 0)\n                      recovering--;\n              } else {\n                  symbol = preErrorSymbol;\n                  preErrorSymbol = null;\n              }\n              break;\n          case 2:\n              len = this.productions_[action[1]][1];\n              yyval.$ = vstack[vstack.length - len];\n              yyval._$ = {first_line: lstack[lstack.length - (len || 1)].first_line, last_line: lstack[lstack.length - 1].last_line, first_column: lstack[lstack.length - (len || 1)].first_column, last_column: lstack[lstack.length - 1].last_column};\n              if (ranges) {\n                  yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]];\n              }\n              r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);\n              if (typeof r !== \"undefined\") {\n                  return r;\n              }\n              if (len) {\n                  stack = stack.slice(0, -1 * len * 2);\n                  vstack = vstack.slice(0, -1 * len);\n                  lstack = lstack.slice(0, -1 * len);\n              }\n              stack.push(this.productions_[action[1]][0]);\n              vstack.push(yyval.$);\n              lstack.push(yyval._$);\n              newState = table[stack[stack.length - 2]][stack[stack.length - 1]];\n              stack.push(newState);\n              break;\n          case 3:\n              return true;\n          }\n      }\n      return true;\n  }\n  };\n\n\n  function stripFlags(open, close) {\n    return {\n      left: open.charAt(2) === '~',\n      right: close.charAt(0) === '~' || close.charAt(1) === '~'\n    };\n  }\n\n  /* Jison generated lexer */\n  var lexer = (function(){\n  var lexer = ({EOF:1,\n  parseError:function parseError(str, hash) {\n          if (this.yy.parser) {\n              this.yy.parser.parseError(str, hash);\n          } else {\n              throw new Error(str);\n          }\n      },\n  setInput:function (input) {\n          this._input = input;\n          this._more = this._less = this.done = false;\n          this.yylineno = this.yyleng = 0;\n          this.yytext = this.matched = this.match = '';\n          this.conditionStack = ['INITIAL'];\n          this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0};\n          if (this.options.ranges) this.yylloc.range = [0,0];\n          this.offset = 0;\n          return this;\n      },\n  input:function () {\n          var ch = this._input[0];\n          this.yytext += ch;\n          this.yyleng++;\n          this.offset++;\n          this.match += ch;\n          this.matched += ch;\n          var lines = ch.match(/(?:\\r\\n?|\\n).*/g);\n          if (lines) {\n              this.yylineno++;\n              this.yylloc.last_line++;\n          } else {\n              this.yylloc.last_column++;\n          }\n          if (this.options.ranges) this.yylloc.range[1]++;\n\n          this._input = this._input.slice(1);\n          return ch;\n      },\n  unput:function (ch) {\n          var len = ch.length;\n          var lines = ch.split(/(?:\\r\\n?|\\n)/g);\n\n          this._input = ch + this._input;\n          this.yytext = this.yytext.substr(0, this.yytext.length-len-1);\n          //this.yyleng -= len;\n          this.offset -= len;\n          var oldLines = this.match.split(/(?:\\r\\n?|\\n)/g);\n          this.match = this.match.substr(0, this.match.length-1);\n          this.matched = this.matched.substr(0, this.matched.length-1);\n\n          if (lines.length-1) this.yylineno -= lines.length-1;\n          var r = this.yylloc.range;\n\n          this.yylloc = {first_line: this.yylloc.first_line,\n            last_line: this.yylineno+1,\n            first_column: this.yylloc.first_column,\n            last_column: lines ?\n                (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length:\n                this.yylloc.first_column - len\n            };\n\n          if (this.options.ranges) {\n              this.yylloc.range = [r[0], r[0] + this.yyleng - len];\n          }\n          return this;\n      },\n  more:function () {\n          this._more = true;\n          return this;\n      },\n  less:function (n) {\n          this.unput(this.match.slice(n));\n      },\n  pastInput:function () {\n          var past = this.matched.substr(0, this.matched.length - this.match.length);\n          return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\\n/g, \"\");\n      },\n  upcomingInput:function () {\n          var next = this.match;\n          if (next.length < 20) {\n              next += this._input.substr(0, 20-next.length);\n          }\n          return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\\n/g, \"\");\n      },\n  showPosition:function () {\n          var pre = this.pastInput();\n          var c = new Array(pre.length + 1).join(\"-\");\n          return pre + this.upcomingInput() + \"\\n\" + c+\"^\";\n      },\n  next:function () {\n          if (this.done) {\n              return this.EOF;\n          }\n          if (!this._input) this.done = true;\n\n          var token,\n              match,\n              tempMatch,\n              index,\n              col,\n              lines;\n          if (!this._more) {\n              this.yytext = '';\n              this.match = '';\n          }\n          var rules = this._currentRules();\n          for (var i=0;i < rules.length; i++) {\n              tempMatch = this._input.match(this.rules[rules[i]]);\n              if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {\n                  match = tempMatch;\n                  index = i;\n                  if (!this.options.flex) break;\n              }\n          }\n          if (match) {\n              lines = match[0].match(/(?:\\r\\n?|\\n).*/g);\n              if (lines) this.yylineno += lines.length;\n              this.yylloc = {first_line: this.yylloc.last_line,\n                             last_line: this.yylineno+1,\n                             first_column: this.yylloc.last_column,\n                             last_column: lines ? lines[lines.length-1].length-lines[lines.length-1].match(/\\r?\\n?/)[0].length : this.yylloc.last_column + match[0].length};\n              this.yytext += match[0];\n              this.match += match[0];\n              this.matches = match;\n              this.yyleng = this.yytext.length;\n              if (this.options.ranges) {\n                  this.yylloc.range = [this.offset, this.offset += this.yyleng];\n              }\n              this._more = false;\n              this._input = this._input.slice(match[0].length);\n              this.matched += match[0];\n              token = this.performAction.call(this, this.yy, this, rules[index],this.conditionStack[this.conditionStack.length-1]);\n              if (this.done && this._input) this.done = false;\n              if (token) return token;\n              else return;\n          }\n          if (this._input === \"\") {\n              return this.EOF;\n          } else {\n              return this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\\n'+this.showPosition(),\n                      {text: \"\", token: null, line: this.yylineno});\n          }\n      },\n  lex:function lex() {\n          var r = this.next();\n          if (typeof r !== 'undefined') {\n              return r;\n          } else {\n              return this.lex();\n          }\n      },\n  begin:function begin(condition) {\n          this.conditionStack.push(condition);\n      },\n  popState:function popState() {\n          return this.conditionStack.pop();\n      },\n  _currentRules:function _currentRules() {\n          return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules;\n      },\n  topState:function () {\n          return this.conditionStack[this.conditionStack.length-2];\n      },\n  pushState:function begin(condition) {\n          this.begin(condition);\n      }});\n  lexer.options = {};\n  lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {\n\n\n  function strip(start, end) {\n    return yy_.yytext = yy_.yytext.substr(start, yy_.yyleng-end);\n  }\n\n\n  var YYSTATE=YY_START\n  switch($avoiding_name_collisions) {\n  case 0:\n                                     if(yy_.yytext.slice(-2) === \"\\\\\\\\\") {\n                                       strip(0,1);\n                                       this.begin(\"mu\");\n                                     } else if(yy_.yytext.slice(-1) === \"\\\\\") {\n                                       strip(0,1);\n                                       this.begin(\"emu\");\n                                     } else {\n                                       this.begin(\"mu\");\n                                     }\n                                     if(yy_.yytext) return 14;\n                                   \n  break;\n  case 1:return 14;\n  break;\n  case 2:\n                                     this.popState();\n                                     return 14;\n                                   \n  break;\n  case 3:strip(0,4); this.popState(); return 15;\n  break;\n  case 4:return 35;\n  break;\n  case 5:return 36;\n  break;\n  case 6:return 25;\n  break;\n  case 7:return 16;\n  break;\n  case 8:return 20;\n  break;\n  case 9:return 19;\n  break;\n  case 10:return 19;\n  break;\n  case 11:return 23;\n  break;\n  case 12:return 22;\n  break;\n  case 13:this.popState(); this.begin('com');\n  break;\n  case 14:strip(3,5); this.popState(); return 15;\n  break;\n  case 15:return 22;\n  break;\n  case 16:return 41;\n  break;\n  case 17:return 40;\n  break;\n  case 18:return 40;\n  break;\n  case 19:return 44;\n  break;\n  case 20:// ignore whitespace\n  break;\n  case 21:this.popState(); return 24;\n  break;\n  case 22:this.popState(); return 18;\n  break;\n  case 23:yy_.yytext = strip(1,2).replace(/\\\\\"/g,'\"'); return 32;\n  break;\n  case 24:yy_.yytext = strip(1,2).replace(/\\\\'/g,\"'\"); return 32;\n  break;\n  case 25:return 42;\n  break;\n  case 26:return 34;\n  break;\n  case 27:return 34;\n  break;\n  case 28:return 33;\n  break;\n  case 29:return 40;\n  break;\n  case 30:yy_.yytext = strip(1,2); return 40;\n  break;\n  case 31:return 'INVALID';\n  break;\n  case 32:return 5;\n  break;\n  }\n  };\n  lexer.rules = [/^(?:[^\\x00]*?(?=(\\{\\{)))/,/^(?:[^\\x00]+)/,/^(?:[^\\x00]{2,}?(?=(\\{\\{|\\\\\\{\\{|\\\\\\\\\\{\\{|$)))/,/^(?:[\\s\\S]*?--\\}\\})/,/^(?:\\()/,/^(?:\\))/,/^(?:\\{\\{(~)?>)/,/^(?:\\{\\{(~)?#)/,/^(?:\\{\\{(~)?\\/)/,/^(?:\\{\\{(~)?\\^)/,/^(?:\\{\\{(~)?\\s*else\\b)/,/^(?:\\{\\{(~)?\\{)/,/^(?:\\{\\{(~)?&)/,/^(?:\\{\\{!--)/,/^(?:\\{\\{![\\s\\S]*?\\}\\})/,/^(?:\\{\\{(~)?)/,/^(?:=)/,/^(?:\\.\\.)/,/^(?:\\.(?=([=~}\\s\\/.)])))/,/^(?:[\\/.])/,/^(?:\\s+)/,/^(?:\\}(~)?\\}\\})/,/^(?:(~)?\\}\\})/,/^(?:\"(\\\\[\"]|[^\"])*\")/,/^(?:'(\\\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=([~}\\s)])))/,/^(?:false(?=([~}\\s)])))/,/^(?:-?[0-9]+(?=([~}\\s)])))/,/^(?:([^\\s!\"#%-,\\.\\/;->@\\[-\\^`\\{-~]+(?=([=~}\\s\\/.)]))))/,/^(?:\\[[^\\]]*\\])/,/^(?:.)/,/^(?:$)/];\n  lexer.conditions = {\"mu\":{\"rules\":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32],\"inclusive\":false},\"emu\":{\"rules\":[2],\"inclusive\":false},\"com\":{\"rules\":[3],\"inclusive\":false},\"INITIAL\":{\"rules\":[0,1,32],\"inclusive\":true}};\n  return lexer;})()\n  parser.lexer = lexer;\n  function Parser () { this.yy = {}; }Parser.prototype = parser;parser.Parser = Parser;\n  return new Parser;\n  })();__exports__ = handlebars;\n  /* jshint ignore:end */\n  return __exports__;\n})();\n\n// handlebars/compiler/base.js\nvar __module8__ = (function(__dependency1__, __dependency2__) {\n  \"use strict\";\n  var __exports__ = {};\n  var parser = __dependency1__;\n  var AST = __dependency2__;\n\n  __exports__.parser = parser;\n\n  function parse(input) {\n    // Just return if an already-compile AST was passed in.\n    if(input.constructor === AST.ProgramNode) { return input; }\n\n    parser.yy = AST;\n    return parser.parse(input);\n  }\n\n  __exports__.parse = parse;\n  return __exports__;\n})(__module9__, __module7__);\n\n// handlebars/compiler/compiler.js\nvar __module10__ = (function(__dependency1__) {\n  \"use strict\";\n  var __exports__ = {};\n  var Exception = __dependency1__;\n\n  function Compiler() {}\n\n  __exports__.Compiler = Compiler;// the foundHelper register will disambiguate helper lookup from finding a\n  // function in a context. This is necessary for mustache compatibility, which\n  // requires that context functions in blocks are evaluated by blockHelperMissing,\n  // and then proceed as if the resulting value was provided to blockHelperMissing.\n\n  Compiler.prototype = {\n    compiler: Compiler,\n\n    disassemble: function() {\n      var opcodes = this.opcodes, opcode, out = [], params, param;\n\n      for (var i=0, l=opcodes.length; i<l; i++) {\n        opcode = opcodes[i];\n\n        if (opcode.opcode === 'DECLARE') {\n          out.push(\"DECLARE \" + opcode.name + \"=\" + opcode.value);\n        } else {\n          params = [];\n          for (var j=0; j<opcode.args.length; j++) {\n            param = opcode.args[j];\n            if (typeof param === \"string\") {\n              param = \"\\\"\" + param.replace(\"\\n\", \"\\\\n\") + \"\\\"\";\n            }\n            params.push(param);\n          }\n          out.push(opcode.opcode + \" \" + params.join(\" \"));\n        }\n      }\n\n      return out.join(\"\\n\");\n    },\n\n    equals: function(other) {\n      var len = this.opcodes.length;\n      if (other.opcodes.length !== len) {\n        return false;\n      }\n\n      for (var i = 0; i < len; i++) {\n        var opcode = this.opcodes[i],\n            otherOpcode = other.opcodes[i];\n        if (opcode.opcode !== otherOpcode.opcode || opcode.args.length !== otherOpcode.args.length) {\n          return false;\n        }\n        for (var j = 0; j < opcode.args.length; j++) {\n          if (opcode.args[j] !== otherOpcode.args[j]) {\n            return false;\n          }\n        }\n      }\n\n      len = this.children.length;\n      if (other.children.length !== len) {\n        return false;\n      }\n      for (i = 0; i < len; i++) {\n        if (!this.children[i].equals(other.children[i])) {\n          return false;\n        }\n      }\n\n      return true;\n    },\n\n    guid: 0,\n\n    compile: function(program, options) {\n      this.opcodes = [];\n      this.children = [];\n      this.depths = {list: []};\n      this.options = options;\n\n      // These changes will propagate to the other compiler components\n      var knownHelpers = this.options.knownHelpers;\n      this.options.knownHelpers = {\n        'helperMissing': true,\n        'blockHelperMissing': true,\n        'each': true,\n        'if': true,\n        'unless': true,\n        'with': true,\n        'log': true\n      };\n      if (knownHelpers) {\n        for (var name in knownHelpers) {\n          this.options.knownHelpers[name] = knownHelpers[name];\n        }\n      }\n\n      return this.accept(program);\n    },\n\n    accept: function(node) {\n      var strip = node.strip || {},\n          ret;\n      if (strip.left) {\n        this.opcode('strip');\n      }\n\n      ret = this[node.type](node);\n\n      if (strip.right) {\n        this.opcode('strip');\n      }\n\n      return ret;\n    },\n\n    program: function(program) {\n      var statements = program.statements;\n\n      for(var i=0, l=statements.length; i<l; i++) {\n        this.accept(statements[i]);\n      }\n      this.isSimple = l === 1;\n\n      this.depths.list = this.depths.list.sort(function(a, b) {\n        return a - b;\n      });\n\n      return this;\n    },\n\n    compileProgram: function(program) {\n      var result = new this.compiler().compile(program, this.options);\n      var guid = this.guid++, depth;\n\n      this.usePartial = this.usePartial || result.usePartial;\n\n      this.children[guid] = result;\n\n      for(var i=0, l=result.depths.list.length; i<l; i++) {\n        depth = result.depths.list[i];\n\n        if(depth < 2) { continue; }\n        else { this.addDepth(depth - 1); }\n      }\n\n      return guid;\n    },\n\n    block: function(block) {\n      var mustache = block.mustache,\n          program = block.program,\n          inverse = block.inverse;\n\n      if (program) {\n        program = this.compileProgram(program);\n      }\n\n      if (inverse) {\n        inverse = this.compileProgram(inverse);\n      }\n\n      var sexpr = mustache.sexpr;\n      var type = this.classifySexpr(sexpr);\n\n      if (type === \"helper\") {\n        this.helperSexpr(sexpr, program, inverse);\n      } else if (type === \"simple\") {\n        this.simpleSexpr(sexpr);\n\n        // now that the simple mustache is resolved, we need to\n        // evaluate it by executing `blockHelperMissing`\n        this.opcode('pushProgram', program);\n        this.opcode('pushProgram', inverse);\n        this.opcode('emptyHash');\n        this.opcode('blockValue');\n      } else {\n        this.ambiguousSexpr(sexpr, program, inverse);\n\n        // now that the simple mustache is resolved, we need to\n        // evaluate it by executing `blockHelperMissing`\n        this.opcode('pushProgram', program);\n        this.opcode('pushProgram', inverse);\n        this.opcode('emptyHash');\n        this.opcode('ambiguousBlockValue');\n      }\n\n      this.opcode('append');\n    },\n\n    hash: function(hash) {\n      var pairs = hash.pairs, pair, val;\n\n      this.opcode('pushHash');\n\n      for(var i=0, l=pairs.length; i<l; i++) {\n        pair = pairs[i];\n        val  = pair[1];\n\n        if (this.options.stringParams) {\n          if(val.depth) {\n            this.addDepth(val.depth);\n          }\n          this.opcode('getContext', val.depth || 0);\n          this.opcode('pushStringParam', val.stringModeValue, val.type);\n\n          if (val.type === 'sexpr') {\n            // Subexpressions get evaluated and passed in\n            // in string params mode.\n            this.sexpr(val);\n          }\n        } else {\n          this.accept(val);\n        }\n\n        this.opcode('assignToHash', pair[0]);\n      }\n      this.opcode('popHash');\n    },\n\n    partial: function(partial) {\n      var partialName = partial.partialName;\n      this.usePartial = true;\n\n      if(partial.context) {\n        this.ID(partial.context);\n      } else {\n        this.opcode('push', 'depth0');\n      }\n\n      this.opcode('invokePartial', partialName.name);\n      this.opcode('append');\n    },\n\n    content: function(content) {\n      this.opcode('appendContent', content.string);\n    },\n\n    mustache: function(mustache) {\n      this.sexpr(mustache.sexpr);\n\n      if(mustache.escaped && !this.options.noEscape) {\n        this.opcode('appendEscaped');\n      } else {\n        this.opcode('append');\n      }\n    },\n\n    ambiguousSexpr: function(sexpr, program, inverse) {\n      var id = sexpr.id,\n          name = id.parts[0],\n          isBlock = program != null || inverse != null;\n\n      this.opcode('getContext', id.depth);\n\n      this.opcode('pushProgram', program);\n      this.opcode('pushProgram', inverse);\n\n      this.opcode('invokeAmbiguous', name, isBlock);\n    },\n\n    simpleSexpr: function(sexpr) {\n      var id = sexpr.id;\n\n      if (id.type === 'DATA') {\n        this.DATA(id);\n      } else if (id.parts.length) {\n        this.ID(id);\n      } else {\n        // Simplified ID for `this`\n        this.addDepth(id.depth);\n        this.opcode('getContext', id.depth);\n        this.opcode('pushContext');\n      }\n\n      this.opcode('resolvePossibleLambda');\n    },\n\n    helperSexpr: function(sexpr, program, inverse) {\n      var params = this.setupFullMustacheParams(sexpr, program, inverse),\n          name = sexpr.id.parts[0];\n\n      if (this.options.knownHelpers[name]) {\n        this.opcode('invokeKnownHelper', params.length, name);\n      } else if (this.options.knownHelpersOnly) {\n        throw new Exception(\"You specified knownHelpersOnly, but used the unknown helper \" + name, sexpr);\n      } else {\n        this.opcode('invokeHelper', params.length, name, sexpr.isRoot);\n      }\n    },\n\n    sexpr: function(sexpr) {\n      var type = this.classifySexpr(sexpr);\n\n      if (type === \"simple\") {\n        this.simpleSexpr(sexpr);\n      } else if (type === \"helper\") {\n        this.helperSexpr(sexpr);\n      } else {\n        this.ambiguousSexpr(sexpr);\n      }\n    },\n\n    ID: function(id) {\n      this.addDepth(id.depth);\n      this.opcode('getContext', id.depth);\n\n      var name = id.parts[0];\n      if (!name) {\n        this.opcode('pushContext');\n      } else {\n        this.opcode('lookupOnContext', id.parts[0]);\n      }\n\n      for(var i=1, l=id.parts.length; i<l; i++) {\n        this.opcode('lookup', id.parts[i]);\n      }\n    },\n\n    DATA: function(data) {\n      this.options.data = true;\n      if (data.id.isScoped || data.id.depth) {\n        throw new Exception('Scoped data references are not supported: ' + data.original, data);\n      }\n\n      this.opcode('lookupData');\n      var parts = data.id.parts;\n      for(var i=0, l=parts.length; i<l; i++) {\n        this.opcode('lookup', parts[i]);\n      }\n    },\n\n    STRING: function(string) {\n      this.opcode('pushString', string.string);\n    },\n\n    INTEGER: function(integer) {\n      this.opcode('pushLiteral', integer.integer);\n    },\n\n    BOOLEAN: function(bool) {\n      this.opcode('pushLiteral', bool.bool);\n    },\n\n    comment: function() {},\n\n    // HELPERS\n    opcode: function(name) {\n      this.opcodes.push({ opcode: name, args: [].slice.call(arguments, 1) });\n    },\n\n    declare: function(name, value) {\n      this.opcodes.push({ opcode: 'DECLARE', name: name, value: value });\n    },\n\n    addDepth: function(depth) {\n      if(depth === 0) { return; }\n\n      if(!this.depths[depth]) {\n        this.depths[depth] = true;\n        this.depths.list.push(depth);\n      }\n    },\n\n    classifySexpr: function(sexpr) {\n      var isHelper   = sexpr.isHelper;\n      var isEligible = sexpr.eligibleHelper;\n      var options    = this.options;\n\n      // if ambiguous, we can possibly resolve the ambiguity now\n      if (isEligible && !isHelper) {\n        var name = sexpr.id.parts[0];\n\n        if (options.knownHelpers[name]) {\n          isHelper = true;\n        } else if (options.knownHelpersOnly) {\n          isEligible = false;\n        }\n      }\n\n      if (isHelper) { return \"helper\"; }\n      else if (isEligible) { return \"ambiguous\"; }\n      else { return \"simple\"; }\n    },\n\n    pushParams: function(params) {\n      var i = params.length, param;\n\n      while(i--) {\n        param = params[i];\n\n        if(this.options.stringParams) {\n          if(param.depth) {\n            this.addDepth(param.depth);\n          }\n\n          this.opcode('getContext', param.depth || 0);\n          this.opcode('pushStringParam', param.stringModeValue, param.type);\n\n          if (param.type === 'sexpr') {\n            // Subexpressions get evaluated and passed in\n            // in string params mode.\n            this.sexpr(param);\n          }\n        } else {\n          this[param.type](param);\n        }\n      }\n    },\n\n    setupFullMustacheParams: function(sexpr, program, inverse) {\n      var params = sexpr.params;\n      this.pushParams(params);\n\n      this.opcode('pushProgram', program);\n      this.opcode('pushProgram', inverse);\n\n      if (sexpr.hash) {\n        this.hash(sexpr.hash);\n      } else {\n        this.opcode('emptyHash');\n      }\n\n      return params;\n    }\n  };\n\n  function precompile(input, options, env) {\n    if (input == null || (typeof input !== 'string' && input.constructor !== env.AST.ProgramNode)) {\n      throw new Exception(\"You must pass a string or Handlebars AST to Handlebars.precompile. You passed \" + input);\n    }\n\n    options = options || {};\n    if (!('data' in options)) {\n      options.data = true;\n    }\n\n    var ast = env.parse(input);\n    var environment = new env.Compiler().compile(ast, options);\n    return new env.JavaScriptCompiler().compile(environment, options);\n  }\n\n  __exports__.precompile = precompile;function compile(input, options, env) {\n    if (input == null || (typeof input !== 'string' && input.constructor !== env.AST.ProgramNode)) {\n      throw new Exception(\"You must pass a string or Handlebars AST to Handlebars.compile. You passed \" + input);\n    }\n\n    options = options || {};\n\n    if (!('data' in options)) {\n      options.data = true;\n    }\n\n    var compiled;\n\n    function compileInput() {\n      var ast = env.parse(input);\n      var environment = new env.Compiler().compile(ast, options);\n      var templateSpec = new env.JavaScriptCompiler().compile(environment, options, undefined, true);\n      return env.template(templateSpec);\n    }\n\n    // Template is only compiled on first use and cached after that point.\n    return function(context, options) {\n      if (!compiled) {\n        compiled = compileInput();\n      }\n      return compiled.call(this, context, options);\n    };\n  }\n\n  __exports__.compile = compile;\n  return __exports__;\n})(__module5__);\n\n// handlebars/compiler/javascript-compiler.js\nvar __module11__ = (function(__dependency1__, __dependency2__) {\n  \"use strict\";\n  var __exports__;\n  var COMPILER_REVISION = __dependency1__.COMPILER_REVISION;\n  var REVISION_CHANGES = __dependency1__.REVISION_CHANGES;\n  var log = __dependency1__.log;\n  var Exception = __dependency2__;\n\n  function Literal(value) {\n    this.value = value;\n  }\n\n  function JavaScriptCompiler() {}\n\n  JavaScriptCompiler.prototype = {\n    // PUBLIC API: You can override these methods in a subclass to provide\n    // alternative compiled forms for name lookup and buffering semantics\n    nameLookup: function(parent, name /* , type*/) {\n      var wrap,\n          ret;\n      if (parent.indexOf('depth') === 0) {\n        wrap = true;\n      }\n\n      if (/^[0-9]+$/.test(name)) {\n        ret = parent + \"[\" + name + \"]\";\n      } else if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {\n        ret = parent + \".\" + name;\n      }\n      else {\n        ret = parent + \"['\" + name + \"']\";\n      }\n\n      if (wrap) {\n        return '(' + parent + ' && ' + ret + ')';\n      } else {\n        return ret;\n      }\n    },\n\n    compilerInfo: function() {\n      var revision = COMPILER_REVISION,\n          versions = REVISION_CHANGES[revision];\n      return \"this.compilerInfo = [\"+revision+\",'\"+versions+\"'];\\n\";\n    },\n\n    appendToBuffer: function(string) {\n      if (this.environment.isSimple) {\n        return \"return \" + string + \";\";\n      } else {\n        return {\n          appendToBuffer: true,\n          content: string,\n          toString: function() { return \"buffer += \" + string + \";\"; }\n        };\n      }\n    },\n\n    initializeBuffer: function() {\n      return this.quotedString(\"\");\n    },\n\n    namespace: \"Handlebars\",\n    // END PUBLIC API\n\n    compile: function(environment, options, context, asObject) {\n      this.environment = environment;\n      this.options = options || {};\n\n      log('debug', this.environment.disassemble() + \"\\n\\n\");\n\n      this.name = this.environment.name;\n      this.isChild = !!context;\n      this.context = context || {\n        programs: [],\n        environments: [],\n        aliases: { }\n      };\n\n      this.preamble();\n\n      this.stackSlot = 0;\n      this.stackVars = [];\n      this.registers = { list: [] };\n      this.hashes = [];\n      this.compileStack = [];\n      this.inlineStack = [];\n\n      this.compileChildren(environment, options);\n\n      var opcodes = environment.opcodes, opcode;\n\n      this.i = 0;\n\n      for(var l=opcodes.length; this.i<l; this.i++) {\n        opcode = opcodes[this.i];\n\n        if(opcode.opcode === 'DECLARE') {\n          this[opcode.name] = opcode.value;\n        } else {\n          this[opcode.opcode].apply(this, opcode.args);\n        }\n\n        // Reset the stripNext flag if it was not set by this operation.\n        if (opcode.opcode !== this.stripNext) {\n          this.stripNext = false;\n        }\n      }\n\n      // Flush any trailing content that might be pending.\n      this.pushSource('');\n\n      if (this.stackSlot || this.inlineStack.length || this.compileStack.length) {\n        throw new Exception('Compile completed with content left on stack');\n      }\n\n      return this.createFunctionContext(asObject);\n    },\n\n    preamble: function() {\n      var out = [];\n\n      if (!this.isChild) {\n        var namespace = this.namespace;\n\n        var copies = \"helpers = this.merge(helpers, \" + namespace + \".helpers);\";\n        if (this.environment.usePartial) { copies = copies + \" partials = this.merge(partials, \" + namespace + \".partials);\"; }\n        if (this.options.data) { copies = copies + \" data = data || {};\"; }\n        out.push(copies);\n      } else {\n        out.push('');\n      }\n\n      if (!this.environment.isSimple) {\n        out.push(\", buffer = \" + this.initializeBuffer());\n      } else {\n        out.push(\"\");\n      }\n\n      // track the last context pushed into place to allow skipping the\n      // getContext opcode when it would be a noop\n      this.lastContext = 0;\n      this.source = out;\n    },\n\n    createFunctionContext: function(asObject) {\n      var locals = this.stackVars.concat(this.registers.list);\n\n      if(locals.length > 0) {\n        this.source[1] = this.source[1] + \", \" + locals.join(\", \");\n      }\n\n      // Generate minimizer alias mappings\n      if (!this.isChild) {\n        for (var alias in this.context.aliases) {\n          if (this.context.aliases.hasOwnProperty(alias)) {\n            this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias];\n          }\n        }\n      }\n\n      if (this.source[1]) {\n        this.source[1] = \"var \" + this.source[1].substring(2) + \";\";\n      }\n\n      // Merge children\n      if (!this.isChild) {\n        this.source[1] += '\\n' + this.context.programs.join('\\n') + '\\n';\n      }\n\n      if (!this.environment.isSimple) {\n        this.pushSource(\"return buffer;\");\n      }\n\n      var params = this.isChild ? [\"depth0\", \"data\"] : [\"Handlebars\", \"depth0\", \"helpers\", \"partials\", \"data\"];\n\n      for(var i=0, l=this.environment.depths.list.length; i<l; i++) {\n        params.push(\"depth\" + this.environment.depths.list[i]);\n      }\n\n      // Perform a second pass over the output to merge content when possible\n      var source = this.mergeSource();\n\n      if (!this.isChild) {\n        source = this.compilerInfo()+source;\n      }\n\n      if (asObject) {\n        params.push(source);\n\n        return Function.apply(this, params);\n      } else {\n        var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\\n  ' + source + '}';\n        log('debug', functionSource + \"\\n\\n\");\n        return functionSource;\n      }\n    },\n    mergeSource: function() {\n      // WARN: We are not handling the case where buffer is still populated as the source should\n      // not have buffer append operations as their final action.\n      var source = '',\n          buffer;\n      for (var i = 0, len = this.source.length; i < len; i++) {\n        var line = this.source[i];\n        if (line.appendToBuffer) {\n          if (buffer) {\n            buffer = buffer + '\\n    + ' + line.content;\n          } else {\n            buffer = line.content;\n          }\n        } else {\n          if (buffer) {\n            source += 'buffer += ' + buffer + ';\\n  ';\n            buffer = undefined;\n          }\n          source += line + '\\n  ';\n        }\n      }\n      return source;\n    },\n\n    // [blockValue]\n    //\n    // On stack, before: hash, inverse, program, value\n    // On stack, after: return value of blockHelperMissing\n    //\n    // The purpose of this opcode is to take a block of the form\n    // `{{#foo}}...{{/foo}}`, resolve the value of `foo`, and\n    // replace it on the stack with the result of properly\n    // invoking blockHelperMissing.\n    blockValue: function() {\n      this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';\n\n      var params = [\"depth0\"];\n      this.setupParams(0, params);\n\n      this.replaceStack(function(current) {\n        params.splice(1, 0, current);\n        return \"blockHelperMissing.call(\" + params.join(\", \") + \")\";\n      });\n    },\n\n    // [ambiguousBlockValue]\n    //\n    // On stack, before: hash, inverse, program, value\n    // Compiler value, before: lastHelper=value of last found helper, if any\n    // On stack, after, if no lastHelper: same as [blockValue]\n    // On stack, after, if lastHelper: value\n    ambiguousBlockValue: function() {\n      this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';\n\n      var params = [\"depth0\"];\n      this.setupParams(0, params);\n\n      var current = this.topStack();\n      params.splice(1, 0, current);\n\n      this.pushSource(\"if (!\" + this.lastHelper + \") { \" + current + \" = blockHelperMissing.call(\" + params.join(\", \") + \"); }\");\n    },\n\n    // [appendContent]\n    //\n    // On stack, before: ...\n    // On stack, after: ...\n    //\n    // Appends the string value of `content` to the current buffer\n    appendContent: function(content) {\n      if (this.pendingContent) {\n        content = this.pendingContent + content;\n      }\n      if (this.stripNext) {\n        content = content.replace(/^\\s+/, '');\n      }\n\n      this.pendingContent = content;\n    },\n\n    // [strip]\n    //\n    // On stack, before: ...\n    // On stack, after: ...\n    //\n    // Removes any trailing whitespace from the prior content node and flags\n    // the next operation for stripping if it is a content node.\n    strip: function() {\n      if (this.pendingContent) {\n        this.pendingContent = this.pendingContent.replace(/\\s+$/, '');\n      }\n      this.stripNext = 'strip';\n    },\n\n    // [append]\n    //\n    // On stack, before: value, ...\n    // On stack, after: ...\n    //\n    // Coerces `value` to a String and appends it to the current buffer.\n    //\n    // If `value` is truthy, or 0, it is coerced into a string and appended\n    // Otherwise, the empty string is appended\n    append: function() {\n      // Force anything that is inlined onto the stack so we don't have duplication\n      // when we examine local\n      this.flushInline();\n      var local = this.popStack();\n      this.pushSource(\"if(\" + local + \" || \" + local + \" === 0) { \" + this.appendToBuffer(local) + \" }\");\n      if (this.environment.isSimple) {\n        this.pushSource(\"else { \" + this.appendToBuffer(\"''\") + \" }\");\n      }\n    },\n\n    // [appendEscaped]\n    //\n    // On stack, before: value, ...\n    // On stack, after: ...\n    //\n    // Escape `value` and append it to the buffer\n    appendEscaped: function() {\n      this.context.aliases.escapeExpression = 'this.escapeExpression';\n\n      this.pushSource(this.appendToBuffer(\"escapeExpression(\" + this.popStack() + \")\"));\n    },\n\n    // [getContext]\n    //\n    // On stack, before: ...\n    // On stack, after: ...\n    // Compiler value, after: lastContext=depth\n    //\n    // Set the value of the `lastContext` compiler value to the depth\n    getContext: function(depth) {\n      if(this.lastContext !== depth) {\n        this.lastContext = depth;\n      }\n    },\n\n    // [lookupOnContext]\n    //\n    // On stack, before: ...\n    // On stack, after: currentContext[name], ...\n    //\n    // Looks up the value of `name` on the current context and pushes\n    // it onto the stack.\n    lookupOnContext: function(name) {\n      this.push(this.nameLookup('depth' + this.lastContext, name, 'context'));\n    },\n\n    // [pushContext]\n    //\n    // On stack, before: ...\n    // On stack, after: currentContext, ...\n    //\n    // Pushes the value of the current context onto the stack.\n    pushContext: function() {\n      this.pushStackLiteral('depth' + this.lastContext);\n    },\n\n    // [resolvePossibleLambda]\n    //\n    // On stack, before: value, ...\n    // On stack, after: resolved value, ...\n    //\n    // If the `value` is a lambda, replace it on the stack by\n    // the return value of the lambda\n    resolvePossibleLambda: function() {\n      this.context.aliases.functionType = '\"function\"';\n\n      this.replaceStack(function(current) {\n        return \"typeof \" + current + \" === functionType ? \" + current + \".apply(depth0) : \" + current;\n      });\n    },\n\n    // [lookup]\n    //\n    // On stack, before: value, ...\n    // On stack, after: value[name], ...\n    //\n    // Replace the value on the stack with the result of looking\n    // up `name` on `value`\n    lookup: function(name) {\n      this.replaceStack(function(current) {\n        return current + \" == null || \" + current + \" === false ? \" + current + \" : \" + this.nameLookup(current, name, 'context');\n      });\n    },\n\n    // [lookupData]\n    //\n    // On stack, before: ...\n    // On stack, after: data, ...\n    //\n    // Push the data lookup operator\n    lookupData: function() {\n      this.pushStackLiteral('data');\n    },\n\n    // [pushStringParam]\n    //\n    // On stack, before: ...\n    // On stack, after: string, currentContext, ...\n    //\n    // This opcode is designed for use in string mode, which\n    // provides the string value of a parameter along with its\n    // depth rather than resolving it immediately.\n    pushStringParam: function(string, type) {\n      this.pushStackLiteral('depth' + this.lastContext);\n\n      this.pushString(type);\n\n      // If it's a subexpression, the string result\n      // will be pushed after this opcode.\n      if (type !== 'sexpr') {\n        if (typeof string === 'string') {\n          this.pushString(string);\n        } else {\n          this.pushStackLiteral(string);\n        }\n      }\n    },\n\n    emptyHash: function() {\n      this.pushStackLiteral('{}');\n\n      if (this.options.stringParams) {\n        this.push('{}'); // hashContexts\n        this.push('{}'); // hashTypes\n      }\n    },\n    pushHash: function() {\n      if (this.hash) {\n        this.hashes.push(this.hash);\n      }\n      this.hash = {values: [], types: [], contexts: []};\n    },\n    popHash: function() {\n      var hash = this.hash;\n      this.hash = this.hashes.pop();\n\n      if (this.options.stringParams) {\n        this.push('{' + hash.contexts.join(',') + '}');\n        this.push('{' + hash.types.join(',') + '}');\n      }\n\n      this.push('{\\n    ' + hash.values.join(',\\n    ') + '\\n  }');\n    },\n\n    // [pushString]\n    //\n    // On stack, before: ...\n    // On stack, after: quotedString(string), ...\n    //\n    // Push a quoted version of `string` onto the stack\n    pushString: function(string) {\n      this.pushStackLiteral(this.quotedString(string));\n    },\n\n    // [push]\n    //\n    // On stack, before: ...\n    // On stack, after: expr, ...\n    //\n    // Push an expression onto the stack\n    push: function(expr) {\n      this.inlineStack.push(expr);\n      return expr;\n    },\n\n    // [pushLiteral]\n    //\n    // On stack, before: ...\n    // On stack, after: value, ...\n    //\n    // Pushes a value onto the stack. This operation prevents\n    // the compiler from creating a temporary variable to hold\n    // it.\n    pushLiteral: function(value) {\n      this.pushStackLiteral(value);\n    },\n\n    // [pushProgram]\n    //\n    // On stack, before: ...\n    // On stack, after: program(guid), ...\n    //\n    // Push a program expression onto the stack. This takes\n    // a compile-time guid and converts it into a runtime-accessible\n    // expression.\n    pushProgram: function(guid) {\n      if (guid != null) {\n        this.pushStackLiteral(this.programExpression(guid));\n      } else {\n        this.pushStackLiteral(null);\n      }\n    },\n\n    // [invokeHelper]\n    //\n    // On stack, before: hash, inverse, program, params..., ...\n    // On stack, after: result of helper invocation\n    //\n    // Pops off the helper's parameters, invokes the helper,\n    // and pushes the helper's return value onto the stack.\n    //\n    // If the helper is not found, `helperMissing` is called.\n    invokeHelper: function(paramSize, name, isRoot) {\n      this.context.aliases.helperMissing = 'helpers.helperMissing';\n      this.useRegister('helper');\n\n      var helper = this.lastHelper = this.setupHelper(paramSize, name, true);\n      var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context');\n\n      var lookup = 'helper = ' + helper.name + ' || ' + nonHelper;\n      if (helper.paramsInit) {\n        lookup += ',' + helper.paramsInit;\n      }\n\n      this.push(\n        '('\n          + lookup\n          + ',helper '\n            + '? helper.call(' + helper.callParams + ') '\n            + ': helperMissing.call(' + helper.helperMissingParams + '))');\n\n      // Always flush subexpressions. This is both to prevent the compounding size issue that\n      // occurs when the code has to be duplicated for inlining and also to prevent errors\n      // due to the incorrect options object being passed due to the shared register.\n      if (!isRoot) {\n        this.flushInline();\n      }\n    },\n\n    // [invokeKnownHelper]\n    //\n    // On stack, before: hash, inverse, program, params..., ...\n    // On stack, after: result of helper invocation\n    //\n    // This operation is used when the helper is known to exist,\n    // so a `helperMissing` fallback is not required.\n    invokeKnownHelper: function(paramSize, name) {\n      var helper = this.setupHelper(paramSize, name);\n      this.push(helper.name + \".call(\" + helper.callParams + \")\");\n    },\n\n    // [invokeAmbiguous]\n    //\n    // On stack, before: hash, inverse, program, params..., ...\n    // On stack, after: result of disambiguation\n    //\n    // This operation is used when an expression like `{{foo}}`\n    // is provided, but we don't know at compile-time whether it\n    // is a helper or a path.\n    //\n    // This operation emits more code than the other options,\n    // and can be avoided by passing the `knownHelpers` and\n    // `knownHelpersOnly` flags at compile-time.\n    invokeAmbiguous: function(name, helperCall) {\n      this.context.aliases.functionType = '\"function\"';\n      this.useRegister('helper');\n\n      this.emptyHash();\n      var helper = this.setupHelper(0, name, helperCall);\n\n      var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');\n\n      var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context');\n      var nextStack = this.nextStack();\n\n      if (helper.paramsInit) {\n        this.pushSource(helper.paramsInit);\n      }\n      this.pushSource('if (helper = ' + helperName + ') { ' + nextStack + ' = helper.call(' + helper.callParams + '); }');\n      this.pushSource('else { helper = ' + nonHelper + '; ' + nextStack + ' = typeof helper === functionType ? helper.call(' + helper.callParams + ') : helper; }');\n    },\n\n    // [invokePartial]\n    //\n    // On stack, before: context, ...\n    // On stack after: result of partial invocation\n    //\n    // This operation pops off a context, invokes a partial with that context,\n    // and pushes the result of the invocation back.\n    invokePartial: function(name) {\n      var params = [this.nameLookup('partials', name, 'partial'), \"'\" + name + \"'\", this.popStack(), \"helpers\", \"partials\"];\n\n      if (this.options.data) {\n        params.push(\"data\");\n      }\n\n      this.context.aliases.self = \"this\";\n      this.push(\"self.invokePartial(\" + params.join(\", \") + \")\");\n    },\n\n    // [assignToHash]\n    //\n    // On stack, before: value, hash, ...\n    // On stack, after: hash, ...\n    //\n    // Pops a value and hash off the stack, assigns `hash[key] = value`\n    // and pushes the hash back onto the stack.\n    assignToHash: function(key) {\n      var value = this.popStack(),\n          context,\n          type;\n\n      if (this.options.stringParams) {\n        type = this.popStack();\n        context = this.popStack();\n      }\n\n      var hash = this.hash;\n      if (context) {\n        hash.contexts.push(\"'\" + key + \"': \" + context);\n      }\n      if (type) {\n        hash.types.push(\"'\" + key + \"': \" + type);\n      }\n      hash.values.push(\"'\" + key + \"': (\" + value + \")\");\n    },\n\n    // HELPERS\n\n    compiler: JavaScriptCompiler,\n\n    compileChildren: function(environment, options) {\n      var children = environment.children, child, compiler;\n\n      for(var i=0, l=children.length; i<l; i++) {\n        child = children[i];\n        compiler = new this.compiler();\n\n        var index = this.matchExistingProgram(child);\n\n        if (index == null) {\n          this.context.programs.push('');     // Placeholder to prevent name conflicts for nested children\n          index = this.context.programs.length;\n          child.index = index;\n          child.name = 'program' + index;\n          this.context.programs[index] = compiler.compile(child, options, this.context);\n          this.context.environments[index] = child;\n        } else {\n          child.index = index;\n          child.name = 'program' + index;\n        }\n      }\n    },\n    matchExistingProgram: function(child) {\n      for (var i = 0, len = this.context.environments.length; i < len; i++) {\n        var environment = this.context.environments[i];\n        if (environment && environment.equals(child)) {\n          return i;\n        }\n      }\n    },\n\n    programExpression: function(guid) {\n      this.context.aliases.self = \"this\";\n\n      if(guid == null) {\n        return \"self.noop\";\n      }\n\n      var child = this.environment.children[guid],\n          depths = child.depths.list, depth;\n\n      var programParams = [child.index, child.name, \"data\"];\n\n      for(var i=0, l = depths.length; i<l; i++) {\n        depth = depths[i];\n\n        if(depth === 1) { programParams.push(\"depth0\"); }\n        else { programParams.push(\"depth\" + (depth - 1)); }\n      }\n\n      return (depths.length === 0 ? \"self.program(\" : \"self.programWithDepth(\") + programParams.join(\", \") + \")\";\n    },\n\n    register: function(name, val) {\n      this.useRegister(name);\n      this.pushSource(name + \" = \" + val + \";\");\n    },\n\n    useRegister: function(name) {\n      if(!this.registers[name]) {\n        this.registers[name] = true;\n        this.registers.list.push(name);\n      }\n    },\n\n    pushStackLiteral: function(item) {\n      return this.push(new Literal(item));\n    },\n\n    pushSource: function(source) {\n      if (this.pendingContent) {\n        this.source.push(this.appendToBuffer(this.quotedString(this.pendingContent)));\n        this.pendingContent = undefined;\n      }\n\n      if (source) {\n        this.source.push(source);\n      }\n    },\n\n    pushStack: function(item) {\n      this.flushInline();\n\n      var stack = this.incrStack();\n      if (item) {\n        this.pushSource(stack + \" = \" + item + \";\");\n      }\n      this.compileStack.push(stack);\n      return stack;\n    },\n\n    replaceStack: function(callback) {\n      var prefix = '',\n          inline = this.isInline(),\n          stack,\n          createdStack,\n          usedLiteral;\n\n      // If we are currently inline then we want to merge the inline statement into the\n      // replacement statement via ','\n      if (inline) {\n        var top = this.popStack(true);\n\n        if (top instanceof Literal) {\n          // Literals do not need to be inlined\n          stack = top.value;\n          usedLiteral = true;\n        } else {\n          // Get or create the current stack name for use by the inline\n          createdStack = !this.stackSlot;\n          var name = !createdStack ? this.topStackName() : this.incrStack();\n\n          prefix = '(' + this.push(name) + ' = ' + top + '),';\n          stack = this.topStack();\n        }\n      } else {\n        stack = this.topStack();\n      }\n\n      var item = callback.call(this, stack);\n\n      if (inline) {\n        if (!usedLiteral) {\n          this.popStack();\n        }\n        if (createdStack) {\n          this.stackSlot--;\n        }\n        this.push('(' + prefix + item + ')');\n      } else {\n        // Prevent modification of the context depth variable. Through replaceStack\n        if (!/^stack/.test(stack)) {\n          stack = this.nextStack();\n        }\n\n        this.pushSource(stack + \" = (\" + prefix + item + \");\");\n      }\n      return stack;\n    },\n\n    nextStack: function() {\n      return this.pushStack();\n    },\n\n    incrStack: function() {\n      this.stackSlot++;\n      if(this.stackSlot > this.stackVars.length) { this.stackVars.push(\"stack\" + this.stackSlot); }\n      return this.topStackName();\n    },\n    topStackName: function() {\n      return \"stack\" + this.stackSlot;\n    },\n    flushInline: function() {\n      var inlineStack = this.inlineStack;\n      if (inlineStack.length) {\n        this.inlineStack = [];\n        for (var i = 0, len = inlineStack.length; i < len; i++) {\n          var entry = inlineStack[i];\n          if (entry instanceof Literal) {\n            this.compileStack.push(entry);\n          } else {\n            this.pushStack(entry);\n          }\n        }\n      }\n    },\n    isInline: function() {\n      return this.inlineStack.length;\n    },\n\n    popStack: function(wrapped) {\n      var inline = this.isInline(),\n          item = (inline ? this.inlineStack : this.compileStack).pop();\n\n      if (!wrapped && (item instanceof Literal)) {\n        return item.value;\n      } else {\n        if (!inline) {\n          if (!this.stackSlot) {\n            throw new Exception('Invalid stack pop');\n          }\n          this.stackSlot--;\n        }\n        return item;\n      }\n    },\n\n    topStack: function(wrapped) {\n      var stack = (this.isInline() ? this.inlineStack : this.compileStack),\n          item = stack[stack.length - 1];\n\n      if (!wrapped && (item instanceof Literal)) {\n        return item.value;\n      } else {\n        return item;\n      }\n    },\n\n    quotedString: function(str) {\n      return '\"' + str\n        .replace(/\\\\/g, '\\\\\\\\')\n        .replace(/\"/g, '\\\\\"')\n        .replace(/\\n/g, '\\\\n')\n        .replace(/\\r/g, '\\\\r')\n        .replace(/\\u2028/g, '\\\\u2028')   // Per Ecma-262 7.3 + 7.8.4\n        .replace(/\\u2029/g, '\\\\u2029') + '\"';\n    },\n\n    setupHelper: function(paramSize, name, missingParams) {\n      var params = [],\n          paramsInit = this.setupParams(paramSize, params, missingParams);\n      var foundHelper = this.nameLookup('helpers', name, 'helper');\n\n      return {\n        params: params,\n        paramsInit: paramsInit,\n        name: foundHelper,\n        callParams: [\"depth0\"].concat(params).join(\", \"),\n        helperMissingParams: missingParams && [\"depth0\", this.quotedString(name)].concat(params).join(\", \")\n      };\n    },\n\n    setupOptions: function(paramSize, params) {\n      var options = [], contexts = [], types = [], param, inverse, program;\n\n      options.push(\"hash:\" + this.popStack());\n\n      if (this.options.stringParams) {\n        options.push(\"hashTypes:\" + this.popStack());\n        options.push(\"hashContexts:\" + this.popStack());\n      }\n\n      inverse = this.popStack();\n      program = this.popStack();\n\n      // Avoid setting fn and inverse if neither are set. This allows\n      // helpers to do a check for `if (options.fn)`\n      if (program || inverse) {\n        if (!program) {\n          this.context.aliases.self = \"this\";\n          program = \"self.noop\";\n        }\n\n        if (!inverse) {\n          this.context.aliases.self = \"this\";\n          inverse = \"self.noop\";\n        }\n\n        options.push(\"inverse:\" + inverse);\n        options.push(\"fn:\" + program);\n      }\n\n      for(var i=0; i<paramSize; i++) {\n        param = this.popStack();\n        params.push(param);\n\n        if(this.options.stringParams) {\n          types.push(this.popStack());\n          contexts.push(this.popStack());\n        }\n      }\n\n      if (this.options.stringParams) {\n        options.push(\"contexts:[\" + contexts.join(\",\") + \"]\");\n        options.push(\"types:[\" + types.join(\",\") + \"]\");\n      }\n\n      if(this.options.data) {\n        options.push(\"data:data\");\n      }\n\n      return options;\n    },\n\n    // the params and contexts arguments are passed in arrays\n    // to fill in\n    setupParams: function(paramSize, params, useRegister) {\n      var options = '{' + this.setupOptions(paramSize, params).join(',') + '}';\n\n      if (useRegister) {\n        this.useRegister('options');\n        params.push('options');\n        return 'options=' + options;\n      } else {\n        params.push(options);\n        return '';\n      }\n    }\n  };\n\n  var reservedWords = (\n    \"break else new var\" +\n    \" case finally return void\" +\n    \" catch for switch while\" +\n    \" continue function this with\" +\n    \" default if throw\" +\n    \" delete in try\" +\n    \" do instanceof typeof\" +\n    \" abstract enum int short\" +\n    \" boolean export interface static\" +\n    \" byte extends long super\" +\n    \" char final native synchronized\" +\n    \" class float package throws\" +\n    \" const goto private transient\" +\n    \" debugger implements protected volatile\" +\n    \" double import public let yield\"\n  ).split(\" \");\n\n  var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};\n\n  for(var i=0, l=reservedWords.length; i<l; i++) {\n    compilerWords[reservedWords[i]] = true;\n  }\n\n  JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {\n    if(!JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name)) {\n      return true;\n    }\n    return false;\n  };\n\n  __exports__ = JavaScriptCompiler;\n  return __exports__;\n})(__module2__, __module5__);\n\n// handlebars.js\nvar __module0__ = (function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__) {\n  \"use strict\";\n  var __exports__;\n  /*globals Handlebars: true */\n  var Handlebars = __dependency1__;\n\n  // Compiler imports\n  var AST = __dependency2__;\n  var Parser = __dependency3__.parser;\n  var parse = __dependency3__.parse;\n  var Compiler = __dependency4__.Compiler;\n  var compile = __dependency4__.compile;\n  var precompile = __dependency4__.precompile;\n  var JavaScriptCompiler = __dependency5__;\n\n  var _create = Handlebars.create;\n  var create = function() {\n    var hb = _create();\n\n    hb.compile = function(input, options) {\n      return compile(input, options, hb);\n    };\n    hb.precompile = function (input, options) {\n      return precompile(input, options, hb);\n    };\n\n    hb.AST = AST;\n    hb.Compiler = Compiler;\n    hb.JavaScriptCompiler = JavaScriptCompiler;\n    hb.Parser = Parser;\n    hb.parse = parse;\n\n    return hb;\n  };\n\n  Handlebars = create();\n  Handlebars.create = create;\n\n  __exports__ = Handlebars;\n  return __exports__;\n})(__module1__, __module7__, __module8__, __module10__, __module11__);\n\n  return __module0__;\n})();\n"
  },
  {
    "path": "webapp/static/js/vendor/table2CSV.js",
    "content": "jQuery.fn.table2CSV = function(options) {\n    var options = jQuery.extend({\n        separator: ',',\n        header: [],\n        delivery: 'popup' // popup, value\n    },\n    options);\n\n    var csvData = [];\n    var headerArr = [];\n    var el = this;\n\n    //header\n    var numCols = options.header.length;\n    var tmpRow = []; // construct header avalible array\n\n    if (numCols > 0) {\n        for (var i = 0; i < numCols; i++) {\n            tmpRow[tmpRow.length] = formatData(options.header[i]);\n        }\n    } else {\n        $(el).filter(':visible').find('th').each(function() {\n            if ($(this).css('display') != 'none') tmpRow[tmpRow.length] = formatData($(this).html());\n        });\n    }\n\n    row2CSV(tmpRow);\n\n    // actual data\n    $(el).find('tr').each(function() {\n        var tmpRow = [];\n        $(this).filter(':visible').find('td').each(function() {\n            if ($(this).css('display') != 'none') tmpRow[tmpRow.length] = formatData($(this).html());\n        });\n        row2CSV(tmpRow);\n    });\n    if (options.delivery == 'popup') {\n        var mydata = csvData.join('\\n');\n        return popup(mydata);\n    } else {\n        var mydata = csvData.join('\\n');\n        return mydata;\n    }\n\n    function row2CSV(tmpRow) {\n        var tmp = tmpRow.join('') // to remove any blank rows\n        // alert(tmp);\n        if (tmpRow.length > 0 && tmp != '') {\n            var mystr = tmpRow.join(options.separator);\n            csvData[csvData.length] = mystr;\n        }\n    }\n    function formatData(input) {\n        // replace \" with “\n        var regexp = new RegExp(/[\"]/g);\n        var output = input.replace(regexp, \"“\");\n        //HTML\n        var regexp = new RegExp(/\\<[^\\<]+\\>/g);\n        var output = output.replace(regexp, \"\");\n        if (output == \"\") return '';\n        return '\"' + output + '\"';\n    }\n    function popup(data) {\n        var generator = window.open('', 'csv', 'height=400,width=600');\n        generator.document.write('<html><head><title>CSV</title>');\n        generator.document.write('</head><body >');\n        generator.document.write('<textArea cols=70 rows=15 wrap=\"off\" >');\n        generator.document.write(data);\n        generator.document.write('</textArea>');\n        generator.document.write('</body></html>');\n        generator.document.close();\n        return true;\n    }\n};"
  },
  {
    "path": "webapp/static/js/vendor/underscore-min.js",
    "content": "(function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.concat,l=u.toString,f=u.hasOwnProperty,s=e.forEach,p=e.map,h=e.reduce,v=e.reduceRight,d=e.filter,g=e.every,m=e.some,y=e.indexOf,b=e.lastIndexOf,x=Array.isArray,_=Object.keys,j=i.bind,w=function(n){return n instanceof w?n:this instanceof w?(this._wrapped=n,void 0):new w(n)};\"undefined\"!=typeof exports?(\"undefined\"!=typeof module&&module.exports&&(exports=module.exports=w),exports._=w):n._=w,w.VERSION=\"1.4.4\";var A=w.each=w.forEach=function(n,t,e){if(null!=n)if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a in n)if(w.has(n,a)&&t.call(e,n[a],a,n)===r)return};w.map=w.collect=function(n,t,r){var e=[];return null==n?e:p&&n.map===p?n.map(t,r):(A(n,function(n,u,i){e[e.length]=t.call(r,n,u,i)}),e)};var O=\"Reduce of empty array with no initial value\";w.reduce=w.foldl=w.inject=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),h&&n.reduce===h)return e&&(t=w.bind(t,e)),u?n.reduce(t,r):n.reduce(t);if(A(n,function(n,i,a){u?r=t.call(e,r,n,i,a):(r=n,u=!0)}),!u)throw new TypeError(O);return r},w.reduceRight=w.foldr=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),v&&n.reduceRight===v)return e&&(t=w.bind(t,e)),u?n.reduceRight(t,r):n.reduceRight(t);var i=n.length;if(i!==+i){var a=w.keys(n);i=a.length}if(A(n,function(o,c,l){c=a?a[--i]:--i,u?r=t.call(e,r,n[c],c,l):(r=n[c],u=!0)}),!u)throw new TypeError(O);return r},w.find=w.detect=function(n,t,r){var e;return E(n,function(n,u,i){return t.call(r,n,u,i)?(e=n,!0):void 0}),e},w.filter=w.select=function(n,t,r){var e=[];return null==n?e:d&&n.filter===d?n.filter(t,r):(A(n,function(n,u,i){t.call(r,n,u,i)&&(e[e.length]=n)}),e)},w.reject=function(n,t,r){return w.filter(n,function(n,e,u){return!t.call(r,n,e,u)},r)},w.every=w.all=function(n,t,e){t||(t=w.identity);var u=!0;return null==n?u:g&&n.every===g?n.every(t,e):(A(n,function(n,i,a){return(u=u&&t.call(e,n,i,a))?void 0:r}),!!u)};var E=w.some=w.any=function(n,t,e){t||(t=w.identity);var u=!1;return null==n?u:m&&n.some===m?n.some(t,e):(A(n,function(n,i,a){return u||(u=t.call(e,n,i,a))?r:void 0}),!!u)};w.contains=w.include=function(n,t){return null==n?!1:y&&n.indexOf===y?n.indexOf(t)!=-1:E(n,function(n){return n===t})},w.invoke=function(n,t){var r=o.call(arguments,2),e=w.isFunction(t);return w.map(n,function(n){return(e?t:n[t]).apply(n,r)})},w.pluck=function(n,t){return w.map(n,function(n){return n[t]})},w.where=function(n,t,r){return w.isEmpty(t)?r?null:[]:w[r?\"find\":\"filter\"](n,function(n){for(var r in t)if(t[r]!==n[r])return!1;return!0})},w.findWhere=function(n,t){return w.where(n,t,!0)},w.max=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.max.apply(Math,n);if(!t&&w.isEmpty(n))return-1/0;var e={computed:-1/0,value:-1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;a>=e.computed&&(e={value:n,computed:a})}),e.value},w.min=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.min.apply(Math,n);if(!t&&w.isEmpty(n))return 1/0;var e={computed:1/0,value:1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;e.computed>a&&(e={value:n,computed:a})}),e.value},w.shuffle=function(n){var t,r=0,e=[];return A(n,function(n){t=w.random(r++),e[r-1]=e[t],e[t]=n}),e};var k=function(n){return w.isFunction(n)?n:function(t){return t[n]}};w.sortBy=function(n,t,r){var e=k(t);return w.pluck(w.map(n,function(n,t,u){return{value:n,index:t,criteria:e.call(r,n,t,u)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index<t.index?-1:1}),\"value\")};var F=function(n,t,r,e){var u={},i=k(t||w.identity);return A(n,function(t,a){var o=i.call(r,t,a,n);e(u,o,t)}),u};w.groupBy=function(n,t,r){return F(n,t,r,function(n,t,r){(w.has(n,t)?n[t]:n[t]=[]).push(r)})},w.countBy=function(n,t,r){return F(n,t,r,function(n,t){w.has(n,t)||(n[t]=0),n[t]++})},w.sortedIndex=function(n,t,r,e){r=null==r?w.identity:k(r);for(var u=r.call(e,t),i=0,a=n.length;a>i;){var o=i+a>>>1;u>r.call(e,n[o])?i=o+1:a=o}return i},w.toArray=function(n){return n?w.isArray(n)?o.call(n):n.length===+n.length?w.map(n,w.identity):w.values(n):[]},w.size=function(n){return null==n?0:n.length===+n.length?n.length:w.keys(n).length},w.first=w.head=w.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:o.call(n,0,t)},w.initial=function(n,t,r){return o.call(n,0,n.length-(null==t||r?1:t))},w.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:o.call(n,Math.max(n.length-t,0))},w.rest=w.tail=w.drop=function(n,t,r){return o.call(n,null==t||r?1:t)},w.compact=function(n){return w.filter(n,w.identity)};var R=function(n,t,r){return A(n,function(n){w.isArray(n)?t?a.apply(r,n):R(n,t,r):r.push(n)}),r};w.flatten=function(n,t){return R(n,t,[])},w.without=function(n){return w.difference(n,o.call(arguments,1))},w.uniq=w.unique=function(n,t,r,e){w.isFunction(t)&&(e=r,r=t,t=!1);var u=r?w.map(n,r,e):n,i=[],a=[];return A(u,function(r,e){(t?e&&a[a.length-1]===r:w.contains(a,r))||(a.push(r),i.push(n[e]))}),i},w.union=function(){return w.uniq(c.apply(e,arguments))},w.intersection=function(n){var t=o.call(arguments,1);return w.filter(w.uniq(n),function(n){return w.every(t,function(t){return w.indexOf(t,n)>=0})})},w.difference=function(n){var t=c.apply(e,o.call(arguments,1));return w.filter(n,function(n){return!w.contains(t,n)})},w.zip=function(){for(var n=o.call(arguments),t=w.max(w.pluck(n,\"length\")),r=Array(t),e=0;t>e;e++)r[e]=w.pluck(n,\"\"+e);return r},w.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},w.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if(\"number\"!=typeof r)return e=w.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}if(y&&n.indexOf===y)return n.indexOf(t,r);for(;u>e;e++)if(n[e]===t)return e;return-1},w.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=null!=r;if(b&&n.lastIndexOf===b)return e?n.lastIndexOf(t,r):n.lastIndexOf(t);for(var u=e?r:n.length;u--;)if(n[u]===t)return u;return-1},w.range=function(n,t,r){1>=arguments.length&&(t=n||0,n=0),r=arguments[2]||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=0,i=Array(e);e>u;)i[u++]=n,n+=r;return i},w.bind=function(n,t){if(n.bind===j&&j)return j.apply(n,o.call(arguments,1));var r=o.call(arguments,2);return function(){return n.apply(t,r.concat(o.call(arguments)))}},w.partial=function(n){var t=o.call(arguments,1);return function(){return n.apply(this,t.concat(o.call(arguments)))}},w.bindAll=function(n){var t=o.call(arguments,1);return 0===t.length&&(t=w.functions(n)),A(t,function(t){n[t]=w.bind(n[t],n)}),n},w.memoize=function(n,t){var r={};return t||(t=w.identity),function(){var e=t.apply(this,arguments);return w.has(r,e)?r[e]:r[e]=n.apply(this,arguments)}},w.delay=function(n,t){var r=o.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},w.defer=function(n){return w.delay.apply(w,[n,1].concat(o.call(arguments,1)))},w.throttle=function(n,t){var r,e,u,i,a=0,o=function(){a=new Date,u=null,i=n.apply(r,e)};return function(){var c=new Date,l=t-(c-a);return r=this,e=arguments,0>=l?(clearTimeout(u),u=null,a=c,i=n.apply(r,e)):u||(u=setTimeout(o,l)),i}},w.debounce=function(n,t,r){var e,u;return function(){var i=this,a=arguments,o=function(){e=null,r||(u=n.apply(i,a))},c=r&&!e;return clearTimeout(e),e=setTimeout(o,t),c&&(u=n.apply(i,a)),u}},w.once=function(n){var t,r=!1;return function(){return r?t:(r=!0,t=n.apply(this,arguments),n=null,t)}},w.wrap=function(n,t){return function(){var r=[n];return a.apply(r,arguments),t.apply(this,r)}},w.compose=function(){var n=arguments;return function(){for(var t=arguments,r=n.length-1;r>=0;r--)t=[n[r].apply(this,t)];return t[0]}},w.after=function(n,t){return 0>=n?t():function(){return 1>--n?t.apply(this,arguments):void 0}},w.keys=_||function(n){if(n!==Object(n))throw new TypeError(\"Invalid object\");var t=[];for(var r in n)w.has(n,r)&&(t[t.length]=r);return t},w.values=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push(n[r]);return t},w.pairs=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push([r,n[r]]);return t},w.invert=function(n){var t={};for(var r in n)w.has(n,r)&&(t[n[r]]=r);return t},w.functions=w.methods=function(n){var t=[];for(var r in n)w.isFunction(n[r])&&t.push(r);return t.sort()},w.extend=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]=t[r]}),n},w.pick=function(n){var t={},r=c.apply(e,o.call(arguments,1));return A(r,function(r){r in n&&(t[r]=n[r])}),t},w.omit=function(n){var t={},r=c.apply(e,o.call(arguments,1));for(var u in n)w.contains(r,u)||(t[u]=n[u]);return t},w.defaults=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)null==n[r]&&(n[r]=t[r])}),n},w.clone=function(n){return w.isObject(n)?w.isArray(n)?n.slice():w.extend({},n):n},w.tap=function(n,t){return t(n),n};var I=function(n,t,r,e){if(n===t)return 0!==n||1/n==1/t;if(null==n||null==t)return n===t;n instanceof w&&(n=n._wrapped),t instanceof w&&(t=t._wrapped);var u=l.call(n);if(u!=l.call(t))return!1;switch(u){case\"[object String]\":return n==t+\"\";case\"[object Number]\":return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case\"[object Date]\":case\"[object Boolean]\":return+n==+t;case\"[object RegExp]\":return n.source==t.source&&n.global==t.global&&n.multiline==t.multiline&&n.ignoreCase==t.ignoreCase}if(\"object\"!=typeof n||\"object\"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]==n)return e[i]==t;r.push(n),e.push(t);var a=0,o=!0;if(\"[object Array]\"==u){if(a=n.length,o=a==t.length)for(;a--&&(o=I(n[a],t[a],r,e)););}else{var c=n.constructor,f=t.constructor;if(c!==f&&!(w.isFunction(c)&&c instanceof c&&w.isFunction(f)&&f instanceof f))return!1;for(var s in n)if(w.has(n,s)&&(a++,!(o=w.has(t,s)&&I(n[s],t[s],r,e))))break;if(o){for(s in t)if(w.has(t,s)&&!a--)break;o=!a}}return r.pop(),e.pop(),o};w.isEqual=function(n,t){return I(n,t,[],[])},w.isEmpty=function(n){if(null==n)return!0;if(w.isArray(n)||w.isString(n))return 0===n.length;for(var t in n)if(w.has(n,t))return!1;return!0},w.isElement=function(n){return!(!n||1!==n.nodeType)},w.isArray=x||function(n){return\"[object Array]\"==l.call(n)},w.isObject=function(n){return n===Object(n)},A([\"Arguments\",\"Function\",\"String\",\"Number\",\"Date\",\"RegExp\"],function(n){w[\"is\"+n]=function(t){return l.call(t)==\"[object \"+n+\"]\"}}),w.isArguments(arguments)||(w.isArguments=function(n){return!(!n||!w.has(n,\"callee\"))}),\"function\"!=typeof/./&&(w.isFunction=function(n){return\"function\"==typeof n}),w.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},w.isNaN=function(n){return w.isNumber(n)&&n!=+n},w.isBoolean=function(n){return n===!0||n===!1||\"[object Boolean]\"==l.call(n)},w.isNull=function(n){return null===n},w.isUndefined=function(n){return n===void 0},w.has=function(n,t){return f.call(n,t)},w.noConflict=function(){return n._=t,this},w.identity=function(n){return n},w.times=function(n,t,r){for(var e=Array(n),u=0;n>u;u++)e[u]=t.call(r,u);return e},w.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))};var M={escape:{\"&\":\"&amp;\",\"<\":\"&lt;\",\">\":\"&gt;\",'\"':\"&quot;\",\"'\":\"&#x27;\",\"/\":\"&#x2F;\"}};M.unescape=w.invert(M.escape);var S={escape:RegExp(\"[\"+w.keys(M.escape).join(\"\")+\"]\",\"g\"),unescape:RegExp(\"(\"+w.keys(M.unescape).join(\"|\")+\")\",\"g\")};w.each([\"escape\",\"unescape\"],function(n){w[n]=function(t){return null==t?\"\":(\"\"+t).replace(S[n],function(t){return M[n][t]})}}),w.result=function(n,t){if(null==n)return null;var r=n[t];return w.isFunction(r)?r.call(n):r},w.mixin=function(n){A(w.functions(n),function(t){var r=w[t]=n[t];w.prototype[t]=function(){var n=[this._wrapped];return a.apply(n,arguments),D.call(this,r.apply(w,n))}})};var N=0;w.uniqueId=function(n){var t=++N+\"\";return n?n+t:t},w.templateSettings={evaluate:/<%([\\s\\S]+?)%>/g,interpolate:/<%=([\\s\\S]+?)%>/g,escape:/<%-([\\s\\S]+?)%>/g};var T=/(.)^/,q={\"'\":\"'\",\"\\\\\":\"\\\\\",\"\\r\":\"r\",\"\\n\":\"n\",\"\t\":\"t\",\"\\u2028\":\"u2028\",\"\\u2029\":\"u2029\"},B=/\\\\|'|\\r|\\n|\\t|\\u2028|\\u2029/g;w.template=function(n,t,r){var e;r=w.defaults({},r,w.templateSettings);var u=RegExp([(r.escape||T).source,(r.interpolate||T).source,(r.evaluate||T).source].join(\"|\")+\"|$\",\"g\"),i=0,a=\"__p+='\";n.replace(u,function(t,r,e,u,o){return a+=n.slice(i,o).replace(B,function(n){return\"\\\\\"+q[n]}),r&&(a+=\"'+\\n((__t=(\"+r+\"))==null?'':_.escape(__t))+\\n'\"),e&&(a+=\"'+\\n((__t=(\"+e+\"))==null?'':__t)+\\n'\"),u&&(a+=\"';\\n\"+u+\"\\n__p+='\"),i=o+t.length,t}),a+=\"';\\n\",r.variable||(a=\"with(obj||{}){\\n\"+a+\"}\\n\"),a=\"var __t,__p='',__j=Array.prototype.join,\"+\"print=function(){__p+=__j.call(arguments,'');};\\n\"+a+\"return __p;\\n\";try{e=Function(r.variable||\"obj\",\"_\",a)}catch(o){throw o.source=a,o}if(t)return e(t,w);var c=function(n){return e.call(this,n,w)};return c.source=\"function(\"+(r.variable||\"obj\")+\"){\\n\"+a+\"}\",c},w.chain=function(n){return w(n).chain()};var D=function(n){return this._chain?w(n).chain():n};w.mixin(w),A([\"pop\",\"push\",\"reverse\",\"shift\",\"sort\",\"splice\",\"unshift\"],function(n){var t=e[n];w.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),\"shift\"!=n&&\"splice\"!=n||0!==r.length||delete r[0],D.call(this,r)}}),A([\"concat\",\"join\",\"slice\"],function(n){var t=e[n];w.prototype[n]=function(){return D.call(this,t.apply(this._wrapped,arguments))}}),w.extend(w.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this);"
  },
  {
    "path": "webapp/static/js/vendor/upload-group.js",
    "content": "$(document).on('change', '.btn-file :file', function() {\n  var input = $(this),\n      numFiles = input.get(0).files ? input.get(0).files.length : 1,\n      label = input.val().replace(/\\\\/g, '/').replace(/.*\\//, '');\n  input.trigger('fileselect', [numFiles, label]);\n});\n\n$(document).ready( function() {\n    $('.btn-file :file').on('fileselect', function(event, numFiles, label) {\n        \n        var input = $(this).parents('.input-group').find(':text'),\n            log = numFiles > 1 ? numFiles + ' files selected' : label;\n        \n        if( input.length ) {\n            input.val(log);\n        } else {\n            if( log ) alert(log);\n        }\n        \n    });\n});"
  },
  {
    "path": "webapp/static/sass/_bootstrap-variables.scss",
    "content": "// Override Bootstrap variables here (defaults from bootstrap-sass v3.3.1.0):\n\n// When true, asset path helpers are used, otherwise the regular CSS `url()` is used.\n// When there no function is defined, `fn('')` is parsed as string that equals the right hand side\n// NB: in Sass 3.3 there is a native function: function-exists(twbs-font-path)\n// $bootstrap-sass-asset-helper: (twbs-font-path(\"\") != unquote('twbs-font-path(\"\")'))\n\n//\n// Variables\n// --------------------------------------------------\n\n//== Colors\n//\n//## Gray and brand colors for use across Bootstrap.\n\n// $gray-base:              #000\n// $gray-darker:            lighten($gray-base, 13.5%) // #222\n// $gray-dark:              lighten($gray-base, 20%)   // #333\n// $gray:                   lighten($gray-base, 33.5%) // #555\n// $gray-light:             lighten($gray-base, 46.7%) // #777\n// $gray-lighter:           lighten($gray-base, 93.5%) // #eee\n\n// $brand-primary:         darken(#428bca, 6.5%)\n// $brand-success:         #5cb85c\n// $brand-info:            #5bc0de\n// $brand-warning:         #f0ad4e\n// $brand-danger:          #d9534f\n\n//== Scaffolding\n//\n//## Settings for some of the most global styles.\n\n//** Background color for `<body>`.\n// $body-bg:               #fff\n//** Global text color on `<body>`.\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//** Link hover decoration.\n// $link-hover-decoration: underline\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 `<code>`, `<kbd>`, and `<pre>`.\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 `<body>`.\n// $headings-font-family:    inherit\n// $headings-font-weight:    500\n// $headings-line-height:    1.1\n// $headings-color:          inherit\n\n//== Iconography\n//\n//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.\n\n//** Load fonts from this directory.\n\n// [converter] Asset helpers such as Sprockets and Node.js Mincer do not resolve relative paths\n// $icon-font-path: if($bootstrap-sass-asset-helper, \"bootstrap/\", \"../fonts/bootstrap/\")\n\n//** File name for all font files.\n// $icon-font-name:          \"glyphicons-halflings-regular\"\n//** Element ID within SVG icon file.\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//== Tables\n//\n//## Customizes the `.table` component with basic values, each used across all table variations.\n\n//** Padding for `<th>`s and `<td>`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//== 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//== Forms\n//\n//##\n\n//** `<input>` background color\n// $input-bg:                       #fff\n//** `<input disabled>` background color\n// $input-bg-disabled:              $gray-lighter\n\n//** Text color for `<input>`s\n// $input-color:                    $gray\n//** `<input>` border color\n// $input-border:                   #ccc\n\n// TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4\n//** Default `.form-control` border radius\n// $input-border-radius:            $border-radius-base\n//** Large `.form-control` border radius\n// $input-border-radius-large:      $border-radius-large\n//** Small `.form-control` border radius\n// $input-border-radius-small:      $border-radius-small\n\n//** Border color for inputs on focus\n// $input-border-focus:             #66afe9\n\n//** Placeholder text color\n// $input-color-placeholder:        #999\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//** Disabled cursor for form controls and buttons.\n// $cursor-disabled:                not-allowed\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//** Deprecated `$dropdown-caret-color` as of v3.1.0\n// $dropdown-caret-color:           #000\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:           1060\n// $zindex-tooltip:           1070\n// $zindex-navbar-fixed:      1030\n// $zindex-modal:             1040\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//** Deprecated `$screen-xs` as of v3.0.1\n// $screen-xs:                  480px\n//** Deprecated `$screen-xs-min` as of v3.2.0\n// $screen-xs-min:              $screen-xs\n//** Deprecated `$screen-phone` as of v3.0.1\n// $screen-phone:               $screen-xs-min\n\n// Small screen / tablet\n//** Deprecated `$screen-sm` as of v3.0.1\n// $screen-sm:                  768px\n// $screen-sm-min:              $screen-sm\n//** Deprecated `$screen-tablet` as of v3.0.1\n// $screen-tablet:              $screen-sm-min\n\n// Medium screen / desktop\n//** Deprecated `$screen-md` as of v3.0.1\n// $screen-md:                  992px\n// $screen-md-min:              $screen-md\n//** Deprecated `$screen-desktop` as of v3.0.1\n// $screen-desktop:             $screen-md-min\n\n// Large screen / wide desktop\n//** Deprecated `$screen-lg` as of v3.0.1\n// $screen-lg:                  1200px\n// $screen-lg-min:              $screen-lg\n//** Deprecated `$screen-lg-desktop` as of v3.0.1\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//== 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//== 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//== 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// Inverted navbar\n// Reset inverted navbar basics\n// $navbar-inverse-color:                      lighten($gray-light, 15%)\n// $navbar-inverse-bg:                         #222\n// $navbar-inverse-border:                     darken($navbar-inverse-bg, 10%)\n\n// Inverted navbar links\n// $navbar-inverse-link-color:                 lighten($gray-light, 15%)\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//== 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//== 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//== 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//== 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//== 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//== 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(adjust-hue($state-success-bg, -10), 5%)\n\n// $state-info-text:                #31708f\n// $state-info-bg:                  #d9edf7\n// $state-info-border:              darken(adjust-hue($state-info-bg, -10), 7%)\n\n// $state-warning-text:             #8a6d3b\n// $state-warning-bg:               #fcf8e3\n// $state-warning-border:           darken(adjust-hue($state-warning-bg, -10), 5%)\n\n// $state-danger-text:              #a94442\n// $state-danger-bg:                #f2dede\n// $state-danger-border:            darken(adjust-hue($state-danger-bg, -10), 5%)\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//== 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:                 $popover-bg\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:           fade_in($popover-border-color, 0.05)\n//** Popover outer arrow fallback color\n// $popover-arrow-outer-fallback-color:  darken($popover-fallback-border-color, 20%)\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//== Modals\n//\n//##\n\n//** Padding applied to the modal body\n// $modal-inner-padding:         15px\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//== 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//== 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//** Variable for setting rounded corners on progress bar.\n// $progress-border-radius:      $border-radius-base\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//== 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 items on hover\n// $list-group-hover-bg:           #f5f5f5\n//** Text color of active list items\n// $list-group-active-color:       $component-active-color\n//** Background color of active list items\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//** Text color for content within active list items\n// $list-group-active-text-color:  lighten($list-group-active-bg, 40%)\n\n//** Text color of disabled list items\n// $list-group-disabled-color:      $gray-light\n//** Background color of disabled list items\n// $list-group-disabled-bg:         $gray-lighter\n//** Text color for content within disabled list items\n// $list-group-disabled-text-color: $list-group-disabled-color\n\n// $list-group-link-color:         #555\n// $list-group-link-hover-color:   $list-group-link-color\n// $list-group-link-heading-color: #333\n\n//== Panels\n//\n//##\n\n// $panel-bg:                    #fff\n// $panel-body-padding:          15px\n// $panel-heading-padding:       10px 15px\n// $panel-footer-padding:        $panel-heading-padding\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//== 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//== Wells\n//\n//##\n\n// $well-bg:                     #f5f5f5\n// $well-border:                 darken($well-bg, 7%)\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//== 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//== 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//== Close\n//\n//##\n\n// $close-font-weight:           bold\n// $close-color:                 #000\n// $close-text-shadow:           0 1px 0 #fff\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//== Type\n//\n//##\n\n//** Horizontal offset for forms and lists.\n// $component-offset-horizontal: 180px\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//** Width of horizontal description list titles\n// $dl-horizontal-offset:        $component-offset-horizontal\n//** Horizontal line color.\n// $hr-border:                   $gray-lighter\n"
  },
  {
    "path": "webapp/static/sass/selectors.scss",
    "content": ".thumbnail-list li div.selection-show {\n    position: absolute;\n    border: 1px dashed red;\n    display: none;\n    pointer-events: none;\n}\n\n  /* selections */\n.repeat-lassos-group {\n  position: absolute;\n  right: -185px;\n  bottom: -35px;\n}\n\n/* rectangularSelector.js classes */\n.selection-box, .table-region {\n  position: absolute;\n  border: 1px dashed rgba(255,87,0,0.8);\n  background: rgba(255,87,0,0.2);\n\n  // positions the border _inside_ the box\n  box-sizing:border-box;\n\n  &:hover {\n    cursor: pointer;\n  }\n}\n\n.selection-box {\n  z-index: 42;\n  width: 0;\n  height: 0;\n  visibility: hidden;\n}\n\n.table-region {\n  top: 0; left: 0;\n  z-index: 21;\n}\n\n\n// we don't need these in newUI\ndiv.table-region .resize-handle {\n  position: absolute;\n  // we don't need the dots.\n  // background-repeat: no-repeat;\n  // background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAEJGlDQ1BJQ0MgUHJvZmlsZQAAOBGFVd9v21QUPolvUqQWPyBYR4eKxa9VU1u5GxqtxgZJk6XtShal6dgqJOQ6N4mpGwfb6baqT3uBNwb8AUDZAw9IPCENBmJ72fbAtElThyqqSUh76MQPISbtBVXhu3ZiJ1PEXPX6yznfOec7517bRD1fabWaGVWIlquunc8klZOnFpSeTYrSs9RLA9Sr6U4tkcvNEi7BFffO6+EdigjL7ZHu/k72I796i9zRiSJPwG4VHX0Z+AxRzNRrtksUvwf7+Gm3BtzzHPDTNgQCqwKXfZwSeNHHJz1OIT8JjtAq6xWtCLwGPLzYZi+3YV8DGMiT4VVuG7oiZpGzrZJhcs/hL49xtzH/Dy6bdfTsXYNY+5yluWO4D4neK/ZUvok/17X0HPBLsF+vuUlhfwX4j/rSfAJ4H1H0qZJ9dN7nR19frRTeBt4Fe9FwpwtN+2p1MXscGLHR9SXrmMgjONd1ZxKzpBeA71b4tNhj6JGoyFNp4GHgwUp9qplfmnFW5oTdy7NamcwCI49kv6fN5IAHgD+0rbyoBc3SOjczohbyS1drbq6pQdqumllRC/0ymTtej8gpbbuVwpQfyw66dqEZyxZKxtHpJn+tZnpnEdrYBbueF9qQn93S7HQGGHnYP7w6L+YGHNtd1FJitqPAR+hERCNOFi1i1alKO6RQnjKUxL1GNjwlMsiEhcPLYTEiT9ISbN15OY/jx4SMshe9LaJRpTvHr3C/ybFYP1PZAfwfYrPsMBtnE6SwN9ib7AhLwTrBDgUKcm06FSrTfSj187xPdVQWOk5Q8vxAfSiIUc7Z7xr6zY/+hpqwSyv0I0/QMTRb7RMgBxNodTfSPqdraz/sDjzKBrv4zu2+a2t0/HHzjd2Lbcc2sG7GtsL42K+xLfxtUgI7YHqKlqHK8HbCCXgjHT1cAdMlDetv4FnQ2lLasaOl6vmB0CMmwT/IPszSueHQqv6i/qluqF+oF9TfO2qEGTumJH0qfSv9KH0nfS/9TIp0Wboi/SRdlb6RLgU5u++9nyXYe69fYRPdil1o1WufNSdTTsp75BfllPy8/LI8G7AUuV8ek6fkvfDsCfbNDP0dvRh0CrNqTbV7LfEEGDQPJQadBtfGVMWEq3QWWdufk6ZSNsjG2PQjp3ZcnOWWing6noonSInvi0/Ex+IzAreevPhe+CawpgP1/pMTMDo64G0sTCXIM+KdOnFWRfQKdJvQzV1+Bt8OokmrdtY2yhVX2a+qrykJfMq4Ml3VR4cVzTQVz+UoNne4vcKLoyS+gyKO6EHe+75Fdt0Mbe5bRIf/wjvrVmhbqBN97RD1vxrahvBOfOYzoosH9bq94uejSOQGkVM6sN/7HelL4t10t9F4gPdVzydEOx83Gv+uNxo7XyL/FtFl8z9ZAHF4bBsrEwAAAAlwSFlzAAALEwAACxMBAJqcGAAAABdJREFUCB1jZGBg+A/EKIAJhQflUCgIAGcRAQkLkdtPAAAAAElFTkSuQmCC);\n  // background-position: center center;\n}\n\ndiv.table-region .n-border {\n  width: calc(100% - 10px);\n  top: -5px;\n  left: 5px;\n  height: 10px;\n}\n\ndiv.table-region .s-border {\n  width: calc(100% - 10px);\n  bottom: -5px;\n  left: 5px;\n  height: 10px;\n}\n\ndiv.table-region .w-border {\n  height: calc(100% - 10px);;\n  left: -5px;\n  top: 5px;\n  width: 10px;\n}\n\ndiv.table-region .e-border {\n  height: calc(100% - 10px);\n  top: 5px;\n  right: -5px;\n  width: 10px;\n}\n\ndiv.table-region .nw-border {\n  width: 10px; height: 10px;\n  top: -5px; left: -5px;\n}\n\ndiv.table-region .ne-border {\n  width: 10px; height: 10px;\n  top: -5px; right: -5px;\n}\n\ndiv.table-region .sw-border {\n  width: 10px; height: 10px;\n  bottom: -5px; left: -5px;\n}\n\ndiv.table-region .se-border {\n  width: 10px; height: 10px;\n  bottom: -5px; right: -5px;\n}\n\ndiv.table-region .n-border:hover {\n  cursor: n-resize;\n}\ndiv.table-region .nw-border:hover {\n  cursor: nw-resize;\n}\ndiv.table-region .ne-border:hover {\n  cursor: ne-resize;\n}\ndiv.table-region .s-border:hover {\n  cursor: s-resize;\n}\ndiv.table-region .sw-border:hover {\n  cursor: sw-resize;\n}\ndiv.table-region .se-border:hover {\n  cursor: se-resize;\n}\ndiv.table-region .w-border:hover {\n  cursor: w-resize;\n}\ndiv.table-region .e-border:hover {\n  cursor: e-resize;\n}\n\n\n\ndiv.table-region button[name=close] {\n  font-weight: bold;\n  border: 0;\n  background-color: transparent;\n  padding: 0;\n  font-size: 20px;\n  position: relative;\n  top: -25px;\n  left: 100%;\n  margin-left: 5px;\n}\n\ndiv.table-region button[name=close]:hover {\n  color: red;\n}\n\n\n\n"
  },
  {
    "path": "webapp/static/sass/styles.scss",
    "content": "// IGNORE THE WARNING BELOW. If you're in styles.scss, you're in the right place. :)\n/*!\n * WARNING: Don't edit this file by hand! Instead, you should be using Compass.\n * Edit the file in webapp/static/sass/styles.scss (or webapp/static/sass/selectors.scss)\n * Then, run `$ compass watch` to automatically re-compile the scss file into \"normal\" CSS on save.\n * Alternatively, run `$ compass compile` to re-compile the SCSS once.\n */\n// IGNORE THAT WARNING. YOU'RE IN THE RIGHT SPOT. \n\n@import \"compass\";\n@import \"bootstrap-compass\";\n@import \"bootstrap-variables\";\n@import \"bootstrap\";\n@import \"bootstrap/theme\";\n@import \"selectors\";\n\n@font-face {  // this may not the most Bootstrappy way to do this? not sure why they aren't loading without this\n\tfont-family: 'Glyphicons Halflings';\n\tsrc: url('glyphicons-halflings-regular.eot');\n\tsrc: url('../fonts/bootstrap/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),\n\t     url('../fonts/bootstrap/glyphicons-halflings-regular.woff') format('woff'),\n\t     url('../fonts/bootstrap/glyphicons-halflings-regular.ttf') format('truetype'),\n\t     url('../fonts/bootstrap/glyphicons-halflings-regular.svg#webfont') format('svg');\n}\n\n$sidebarWidth: 195px;\n\nbody {\n\tpadding-top: 70px;\n}\n\n.jumbotron {\n\th1 {\n\t\tfont-size: 2em;\n\t}\n\th2, h3, h4, h5, h6 {\n\t\tfont-size: 1.3em;\n\t}\n\tp {\n\t\tfont-size: 1.3em;\n\t}\n}\n\n\n.navbar-fixed-top\t.container {\n    width: 95%;\n    margin: 0 auto;\n\t}\n\n#navbar .active {\n\tfont-weight: 500;\n\tcolor: $gray-dark;\n}\n\n.navbar-default a.navbar-brand {\n\tpadding-left: 30px;\n\tposition: relative;\n\tfont-weight: bold; \n\tcolor: black;\n\t&::before {\n\t\tposition: absolute;\n\t\tcontent: \"\";\n\t\tdisplay: block;\n\t\tbackground-image: url(\"../img/logo.png\");\n\t\tbackground-repeat: no-repeat;\n\t\tbackground-size: 25px 30px;\n\t\twidth: 25px;\n\t\theight: 30px;\n\t\tleft: 0;\n\t\ttop: 10px;\n\t}\n}\t\n\n.btn-file {\n    position: relative;\n    overflow: hidden;\n}\n.btn-file input[type=file] {\n    position: absolute;\n    top: 0;\n    right: 0;\n    min-width: 100%;\n    min-height: 100%;\n    font-size: 100px;\n    text-align: right;\n    filter: alpha(opacity=0);\n    opacity: 0;\n    outline: none;\n    background: white;\n    cursor: inherit;\n    display: block; \n}\n\n.form-inline .input-group > .form-control {\n\tbackground: white;\n\twidth: 500px;\n}\n\nform {\n\tmargin-bottom: 3em;\n}\n\n#file-list-container {\n\tmax-height: 500px;\n\toverflow-y: scroll;\n\n\t.file-list {\n\tthead tr th {\n\t\ttext-align: center;\n\t\tcursor: pointer;\n\t\tposition: relative;\n\t\tborder-right: 1px solid $table-border-color; \n\t\tpadding-right: 20px;\n\t\t&::before, &::after {\n\t\t\ttext-align: right;\n\t\t\twidth: 11px;\n\t\t\tcolor: $table-border-color; \n\t\t  position: absolute;\n\t\t  display: block;\n\t\t  font-family: 'Glyphicons Halflings';\n\t\t  font-size: .8em;\n\t\t  font-style: normal;\n\t\t  font-weight: normal;\n\t\t  line-height: 1;\n\t\t  -webkit-font-smoothing: antialiased;\n\t\t  -moz-osx-font-smoothing: grayscale;\n\t\t}\n\t\t&::before {\n\t\t  content: \"\\e113\";\n\t\t  right: 3px;\n\t\t  top: 6px;\n\t\t}\n\t\t&::after {\n\t\t  content: \"\\e114\";\n\t\t  right: 4px;\n\t\t  bottom: 6px;\n\t\t}\n\t\t&.headerSortUp::before {\n\t\t\tcolor: $gray-light !important;\n\t\t}\n\t\t&.headerSortDown:after {\n\t\t\tcolor: $gray-light !important;\n\t\t}\n\t\t&:first-of-type {\n\t\t\ttext-align: left;\n\t\t}\n\t\t&:nth-child(n+5) { // nonsortable columns\n\t\t\tcursor: default;\n\t\t\tpadding-right: 8px; // bootstrap default\n\t\t\t&::before, &::after {\n\t\t\t\tcontent: \"\";\n\t\t\t\tdisplay: none;\n\t\t\t\tposition: relative;\n\t\t\t}\n\t\t}\n\t}\n\ttbody tr {\n\t\tbackground: white;\n\t\t&:hover {\n\t\t\tbackground: #d9edf7;\n\t\t}\n\t\ttd{\n\t\t\tline-height: 2.25;\n\t\t\ttext-align: center;\n\t\t\t&:first-of-type {\n\t\t\t\tfont-weight: bold;\n\t\t\t\ttext-align: left;\n\t\t\t}\n\t\t\ta {\n\t\t\t\tcolor: #333; \n\t\t\t}\n\t\t}\n\t}\n}\t\n\n}\n\n.glyphicon-remove {\n\tcolor: $gray-light;\n\t&:hover {\n\t\tcolor: $brand-danger;\n\t}\n}\n\n#sidebar {\n\tbackground: $gray-lighter;\n\twidth: $sidebarWidth;\n\tpadding: 1em 0 0;\n\theight: calc(100% - 51px);\n\ttext-align: center;\n\toverflow-y: scroll;\n\toverflow-x: hidden;\n\tposition: fixed;  \n\tleft: 0;\n\ttop: 51px;\n\tz-index: 2;\n\t@include box-shadow ( inset -.25em 0 .5em -.25em rgba(0,0,0,0.1) );\n\th5 {\n\t\tborder-top: 1px solid $gray-light;\n\t\tpadding-top: 1em;\n\t\tmargin-top: 1em;\n\t}\n\t.btn-group button {\n\t\twidth: 83px;\n\t\tmargin-bottom: 10px;\n\t}\n\tp {\n\t\tfont-size: .9em;\n\t}\n\t.thumbnail-list {\n\t\tpadding-left: 0px;\n\n\t\t.page  {\n\t\t\tmargin: 0 auto 1.25em;\n\t\t\tdisplay: block;\n\t\t\twidth: 90%;\n\t\t\tpadding: 1em .5em .5em 1em;\n\t\t\tposition: relative;\n\t\t\timg {\n\t\t\t\tdisplay: block;\n\t\t\t\twidth: 100%;\n\t\t\t}\n\t\t\tp {\n\t\t\t\tmargin-top: .25em;\n\t\t\t\tcolor: $gray;\n\t\t\t\tline-height: 1;\n\t\t\t}\n\t\t\t&:hover {\n\t\t\t\timg {\n\t\t\t\t\tcursor: pointer;\n\t\t\t\t\t@include box-shadow ( 0 0 0 .1em rgba(0,0,0,0.1) );\n\t\t\t\t}\n\t\t\t}\t\n\t\t\t&.active {\n\t\t\t\timg {\n\t\t\t\t\t@include box-shadow ( 0 0 0 .1em $brand-info );\n\t\t\t\t}\n\t\t\t}\n\t\t\t.remove {\n\t\t\t\tposition: absolute;\n\t\t\t\tleft: -.25em; \n\t\t\t\ttop: 1em;\n\t\t\t\theight: 1em;\n\t\t\t\tdisplay: block;\n\t\t\t\tline-height: 1;\n\t\t\t\tfont-size: 1em;\n\t\t\t\t&:hover {\n\t\t\t\t\tcursor: pointer;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n#control-panel {\n\tposition: fixed;\n\ttop: 50px;\n\tleft: $sidebarWidth;\n\twidth: calc(100% - 200px);\n\tz-index: 101; /* gotta be >100, which is the max z-index for selections */\n\tbackground: #d9edf7;\n\tpadding: 1em;\n\t@include box-shadow ( 0 1px 5px rgba(0, 0, 0, 0.075) );\n\tbutton {\n\t\tmargin-right: 1.25em;\n\t}\n\n\t.filename {\n\t\tdisplay: inline-block;\n\t\tmargin-right: 20px;\n\t\tmax-width: 270px;\n\t  white-space: nowrap;\n\t  overflow: hidden;\n\t  text-overflow: ellipsis;\n\t}\n\tspan.filename {\n\t\tvertical-align: middle;\n\t}\n\n  #template-dropdown-container{\n\t\tul {\n\t\t\tpadding-left: 20px;\n\t\t}\n\t\tbutton { // this is the autodetected tables button\n\t\t\tpadding-left: 0px;\n\t\t}\n\t\tul:first-of-type {\n\t\t\tmargin-bottom: 0px; // we're trying to make the template library <ul> and the <ul> that contains only the autodetected tables one look as if they're one <ul>\n\t\t}\n\t\tli a{\n\t\t\tcursor: pointer;\n\t\t\tcolor: #333;\n\t\t}\n\t}\n\t#template-dropdown-templates-list-container li a {\n\t\tcursor: pointer;\n\t\tcolor: #333;\n\t}\n}\n\n\n\n#main-pane {\n\tbackground: $gray-light;\n\tpadding: 4.25em 2em 2em 2em;\n\tmargin-left: $sidebarWidth; \n\theight: 100%;\n\twidth: calc(100% - 200px);\n\tz-index: 1;\n\t.pdf-page {\n\t\tposition: relative; // used for positioning page numbers\n\t\t.page-number {\n\t\t\tposition: absolute;\n\t\t}\n\t}\n\t.page {\n\t\twidth: 100%;\n\t\tmax-width: 800px;\n\t\tmin-width: 560px;\n\t\t@include box-shadow ( 0 0 2em rgba(0,0,0,0.4) );\n\t\tposition: relative;\n\t\tmargin: 0 auto;\n\t\timg {\n\t\t\tmargin: 2em 0;\n\t\t\tdisplay: block;\n\t\t\twidth: 100%;\n\t\t\tmax-width: 800px;\n\t\t\tmin-width: 560px;\n\t\t\t&:hover {\n\t\t\t\tcursor: crosshair;\n\t\t\t}\n\t\t\tuser-select: none;\n\t\t\t-moz-user-select: none;\n\t\t\t-webkit-user-select: none;\n\t\t\t-ms-user-select: none;\n\t\t}\t\t\n\t}\n\t.selection-box, .table-region {\n\t\tborder: 3px dashed rgba(224, 1, 1, 0.6);\n\t\tbackground: rgba(224,1,1,0.2);\n\t\t.selection-panel {\n\t\t\tdisplay: none;\n\t\t\tposition: absolute;\n\t\t\tbottom: -2.8em;\n\t\t\tleft: 0;\n\t\t\tmin-width: 320px;\n\t\t\tbutton:hover {\n\t\t\t\t\tcursor: pointer;\n\t\t\t}\n\t\t}\n\t\t&:hover {\n\t\t\tcursor: move;\n\t\t\t.selection-panel {\n\t\t\t\tdisplay: block;\n\t\t\t}\t\n\t\t}\n\t}\n}\n\n\nbody.page-selections {\n\tpadding-top: 50px;\n\tbackground: $gray-light;\n\t#main-pane {\n\t\tbackground: $gray-light;\n\t}\n}\n\nbody.page-export {\n\tpadding-top: 50px;\n\tbackground: white;\n\t#sidebar {\n\t\ttext-align: left;\n\t\tpadding: .5em;\n\t\t.lattice.glyphicon {\n\t\t\tcolor: #ededed;\n\t\t\tbackground: #666;\n\t\t\ttext-shadow: none;\n\t\t\tborder: solid #666;\n\t\t\tborder-width: 0 0 1px 1px;\n\t\t}\n\t}\n\t#main-pane {\n\t\tbackground: white;\n\t\tpadding-top: 5.5em;\n\t\t#control-panel {\n\t\t\tform {\n\t\t\t\tdisplay: inline-block;\n\t\t\t\tmargin-bottom: 0;\n\t\t\t\t.form-control {\n\t\t\t\t\twidth: 100px;\n\t\t\t\t\tmargin-right: 1em;\n\t\t\t\t\tdisplay: inline-block;\n\t\t\t\t\t&.format {\n\t\t\t\t\t\twidth: 130px;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t#copy-csv-to-clipboard {\n\t\t\t\t\tmin-width: 140px;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\ttable {\n\t\t\tmargin-top: 2em;\n\t\t}\n\t}\n}\n\n.jumbotron.about p{\n\tfont-size:1.1em;\n}\n\ndiv.spinner {\n\ttop: 10px !important;\n}\n\n#progress-container h5 {\n\tdisplay: inline-block;\n\tfont-size: 1.1em;\n\tfont-weight: bold;\n}\n#progress-container #message {\n\tcolor: #aaa;\n}\n\n.autodetect-in-progress .glyphicon-refresh,\n#download-data.download-in-progress .glyphicon-refresh {\n  animation:  4s linear 0s normal none infinite running spin;\n  display: inline-block;\n}\n\n@-moz-keyframes spin {\n  0% {\n    -moz-transform: rotate(0deg);\n  }\n  100% {\n    -moz-transform: rotate(359deg);\n  }\n}\n@-webkit-keyframes spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n  }\n}\n@-o-keyframes spin {\n  0% {\n    -o-transform: rotate(0deg);\n  }\n  100% {\n    -o-transform: rotate(359deg);\n  }\n}\n@keyframes spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n    transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n    transform: rotate(359deg);\n  }\n}\n\n.autodetect-in-progress .glyphicon-flash {\n\tdisplay: none;\n}\n.autodetect-finished .glyphicon-flash {\n\tdisplay: inline;\n}\n.autodetect-finished .glyphicon-refresh {\n\tdisplay: none;\n}\n#download-data {\n\t&.download-in-progress .glyphicon-download {\n\t\tdisplay: none;\n\t}\n\t.glyphicon-download {\n\t\tdisplay: inline;\n\t}\n\t.glyphicon-refresh {\n\t\tdisplay: none;\n\t}\n}\n\n.flash{\n  -moz-animation: flash 2s ease-out;\n  -moz-animation-iteration-count: 1;\n  -webkit-animation: flash 2s ease-out;\n  -webkit-animation-iteration-count: 1;\n  -ms-animation: flash 2s ease-out;\n  -ms-animation-iteration-count: 1;\n}\n\n@-webkit-keyframes flash {\n    0% { background-color:none;}\n    50% { background-color:#fbf8b2;}        \n    100% {background-color:none;}\n}\n\n@-moz-keyframes flash {\n    0% { background-color:none;}\n    50% { background-color:#fbf8b2;}        \n    100% {background-color:none;}\n}\n\n@-ms-keyframes flash {\n    0% { background-color:none;}\n    50% { background-color:#fbf8b2;}        \n    100% {background-color:none;}\n}\n\n\n#loading {\n\tpadding-left: 30px;\n\t#spinner {\n\t\tposition: relative;\n\t\ttop: 6px;\n\t\tmargin-right: 5px;\n\t}\n}\n"
  },
  {
    "path": "webapp/tabula_debug.rb",
    "content": "require 'json'\n\nclass TabulaDebug < Cuba\n  define do\n\n    on \":file_id/characters\" do |file_id|\n      par = JSON.load(req.params['coords']).first\n      page = par['page']\n\n      pdf_path = File.join(TabulaSettings::DOCUMENTS_BASEPATH, file_id, 'document.pdf')\n      extractor = Tabula::Extraction::ObjectExtractor.new(pdf_path, [page])\n\n      text_elements = extractor.extract.next.get_text([par['y1'].to_f,\n                                                       par['x1'].to_f,\n                                                       par['y2'].to_f,\n                                                       par['x2'].to_f])\n\n      res['Content-Type'] = 'application/json'\n      res.write text_elements.map { |te|\n        { 'left' => te.left,\n          'top' => te.top,\n          'width' => te.width,\n          'height' => te.height,\n          'text' => te.text }\n      }.to_json\n    end\n\n    on \":file_id/text_chunks\" do |file_id|\n      par = JSON.load(req.params['coords']).first\n      page = par['page']\n\n      pdf_path = File.join(TabulaSettings::DOCUMENTS_BASEPATH, file_id, 'document.pdf')\n      extractor = Tabula::Extraction::ObjectExtractor.new(pdf_path, [page])\n\n      text_elements = extractor.extract.next.get_text([par['y1'].to_f,\n                                                       par['x1'].to_f,\n                                                       par['y2'].to_f,\n                                                       par['x2'].to_f])\n\n      text_chunks = Tabula::TextElement.merge_words(text_elements)\n\n      puts text_chunks.inspect\n\n      res['Content-Type'] = 'application/json'\n      res.write text_chunks.map { |te|\n        { 'left' => te.left,\n          'top' => te.top,\n          'width' => te.width,\n          'height' => te.height,\n          'text' => te.text }\n      }.to_json\n    end\n\n\n    on \":file_id/clipping_paths\" do |file_id|\n      par = JSON.load(req.params['coords']).first\n      page = par['page']\n\n      pdf_path = File.join(TabulaSettings::DOCUMENTS_BASEPATH, file_id, 'document.pdf')\n      extractor = Tabula::Extraction::ObjectExtractor.new(pdf_path, [page])\n      extractor.debug_clipping_paths = true\n\n      extractor.extract.next\n\n      res['Content-Type'] = 'application/json'\n      res.write extractor.clipping_paths.map { |cp|\n        {\n          'left' => cp.left,\n          'top' => cp.top,\n          'width' => cp.width,\n          'height' => cp.height\n        }\n      }.to_json\n    end\n\n    on \":file_id/rulings\" do |file_id|\n      par = JSON.load(req.params['coords']).first\n      page = par['page']\n\n      pdf_path = File.join(TabulaSettings::DOCUMENTS_BASEPATH, file_id, 'document.pdf')\n      extractor = Tabula::Extraction::ObjectExtractor.new(pdf_path, [page])\n\n      # crop lines to area of interest\n      par = JSON.load(req.params['coords']).first\n      top, left, bottom, right = [par['y1'].to_f,\n                                  par['x1'].to_f,\n                                  par['y2'].to_f,\n                                  par['x2'].to_f]\n\n      area = Tabula::ZoneEntity.new(top, left,\n                                    right - left, bottom - top)\n\n      page_obj = extractor.extract.next\n      page_area = page_obj.get_area(area)\n      rulings = page_area.ruling_lines\n\n      intersections = {}\n      if req.params['show_intersections'] != 'false'\n        intersections = Tabula::Ruling.find_intersections(page_area.horizontal_ruling_lines,\n                                                          page_area.vertical_ruling_lines)\n      end\n\n      res['Content-Type'] = 'application/json'\n      res.write({:rulings => rulings.uniq, :intersections => intersections.keys }.to_json)\n    end\n\n  end\nend\n"
  },
  {
    "path": "webapp/tabula_job_progress.rb",
    "content": "require_relative '../lib/tabula_job_executor/executor.rb'\n\n# if this is true, then the progress bar will complete (and give the user their PDF to interact with) before\n# the autodetect tables job is done. the JS UI will handle checking periodiclaly if the autodetect tables job \n# is done yet; when it is, it'll be enabled.\nFINISH_BEFORE_AUTODETECT_IS_DONE = true\n\nclass TabulaJobProgress < Cuba\n  define do\n    on \":upload_id/json\" do |batch_id|\n      # upload_id is the \"job id\" uuid that resque-status provides\n      batch = Tabula::Background::JobExecutor.get_by_batch(batch_id)\n      res['Content-Type'] = 'application/json'\n      progress = {}\n      if batch.empty?\n        res.status = 404\n        progress[:status] = \"error\"\n        progress[:message] = \"No such job\"\n        progress[:error_type] = \"no-such-job\"\n        progress[:pct_complete] = 0\n      elsif batch.any?{|uuid, job| job.failed? && job.kind_of?(GenerateDocumentDataJob) && job.message.first.include?(\"NoTextDataException\") }\n        progress[:status] = \"error\"\n        progress[:error_type] = \"no-text\"\n        progress[:message] = \"Fatal Error: No text data is contained in this PDF file. Tabula can't process it.\"\n        progress[:pct_complete] = 99\n        res.write progress.to_json\n      elsif batch.any? { |uuid, job| job.failed? }\n        job =  batch.find{|uuid, job| job.failed? }.last\n        progress[:status] = \"error\"\n        progress[:error_type] = \"unknown\"\n        progress[:message] = \"Sorry, your file upload could not be processed. Please double-check that the file you uploaded is a valid PDF file and try again.\"\n        progress[:pct_complete] = 99\n        res.write progress.to_json\n      else\n        batch.reject!{|uuid, job| FINISH_BEFORE_AUTODETECT_IS_DONE && job.kind_of?(DetectTablesJob ) && job.working? }\n        first_working_job = batch.sort_by{|uuid, job| job.pct_complete}.find { |uuid, job| job.working? }\n        first_working_job_with_message = batch.sort_by{|uuid, job| job.pct_complete}.find { |uuid, job| job.working? && !job.message.nil? && !job.message.empty? }\n\n        progress[:messages] = batch.map{|job| (msg = job.last.message).nil? ? nil : msg.first }.compact\n        progress[:warnings] = batch.map{|job| (msg = job.last.warning).nil? ? nil : msg.first }.compact\n        progress[:message] = !first_working_job_with_message.nil? ? first_working_job_with_message.last.message.first : ''\n        progress[:status] = !first_working_job.nil? ? first_working_job.last.status['status'] : 'completed'\n        progress[:pct_complete] = (batch.inject(0.0) { |sum, (uuid, job)| sum + job.pct_complete } / batch.size).to_i\n        progress[:file_id] = req.params['file_id']\n        progress[:upload_id] = batch_id\n        res.write progress.to_json\n      end\n    end\n\n    on \":upload_id\" do |batch_id|\n      # upload_id is the \"job id\" uuid that resque-status provides\n      batch = Tabula::Background::JobExecutor.get_by_batch(batch_id)\n\n      if batch.empty?\n        res.status = 404\n        res.write \"\"\n        res.write view(\"upload_error.html\",\n                       :message => \"invalid upload_id (TODO: make this generic 404)\")\n      elsif batch.any? { |uuid, job| job.failed? }\n        res.write view(\"upload_error.html\",\n                       :message => \"Sorry, your file upload could not be processed. Please double-check that the file you uploaded is a valid PDF file and try again.\")\n      else\n        s = batch.find { |uuid, job| job.working? }\n        res.write view(\"upload_status.html\",\n                       :status => !s.nil? ? s.last.message : ['completed'],\n                       :pct_complete => (batch.inject(0.0) { |sum, (uuid, job)| sum + job.pct_complete } / batch.size).to_i,\n                       :upload_id => batch_id,\n                       :file_id => req.params['file_id'])\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "webapp/tabula_settings.rb",
    "content": "# encoding: UTF-8\nrequire 'fileutils'\n\nmodule TabulaSettings\n\n  ########## Defaults ##########\n  DEFAULT_DEBUG = false\n  DEFAULT_DISABLE_VERSION_CHECK = false\n  DEFAULT_DISABLE_NOTIFICATIONS = false\n\n  ########## Helpers ##########\n  def self.getDataDir\n    # OS X: ~/Library/Application Support/Tabula\n    # Win:  %APPDATA%/Tabula\n    # Linux: ~/.tabula\n\n    # when invoking as \"java -Dtabula.data_dir=/foo/bar ... -jar tabula.war\"\n    data_dir = java.lang.System.getProperty('tabula.data_dir')\n    unless data_dir.nil?\n      return java.io.File.new(data_dir).getPath\n    end\n\n    # when invoking with env var\n    data_dir = ENV['TABULA_DATA_DIR']\n    unless data_dir.nil?\n      return java.io.File.new(data_dir).getPath\n    end\n\n    # use the usual directory in (system-dependent) user home dir\n    data_dir = nil\n    case java.lang.System.getProperty('os.name')\n    when /Windows/\n      # APPDATA is in a different place (under user.home) depending on\n      # Windows OS version. so use that env var directly, basically\n      appdata = ENV['APPDATA']\n      if appdata.nil?\n        home = java.lang.System.getProperty('user.home')\n      end\n      data_dir = java.io.File.new(appdata, '/Tabula').getPath\n\n    when /Mac/\n      home = java.lang.System.getProperty('user.home')\n      data_dir = File.join(home, '/Library/Application Support/Tabula')\n\n\n    else\n      # probably *NIX\n      home = java.lang.System.getenv('XDG_DATA_HOME')\n      if !home.nil?\n        # XDG\n        data_dir = File.join(home, '/tabula')\n      else\n        # other, normal *NIX systems\n        home = java.lang.System.getProperty('user.home')\n        home = '.' if home.nil?\n        data_dir = File.join(home, '/.tabula')\n      end\n    end # /case\n\n    data_dir\n  end\n\n  def self.enableDebug\n    # when invoking as \"java -Dtabula.debug=1 ... -jar tabula.war\"\n    debug = java.lang.System.getProperty('tabula.debug')\n    unless debug.nil?\n      return (debug.to_i > 0)\n    end\n\n    # when invoking with env var\n    debug = ENV['TABULA_DEBUG']\n    unless debug.nil?\n      return (debug.to_i > 0)\n    end\n\n    DEFAULT_DEBUG\n  end\n\n  def self.disableVersionCheck\n    disable_version_check = java.lang.System.getProperty('tabula.disable_version_check')\n    unless disable_version_check.nil?\n      return (disable_version_check.to_i > 0)\n    end\n\n    DEFAULT_DISABLE_VERSION_CHECK\n  end\n\n  def self.disableNotifications\n    disable_notifications = java.lang.System.getProperty('tabula.disable_notifications')\n    unless disable_notifications.nil?\n      return (disable_notifications.to_i > 0)\n    end\n\n    DEFAULT_DISABLE_NOTIFICATIONS\n  end\n\n  ########## Constants that are used around the app, based on settings ##########\n  DOCUMENTS_BASEPATH = File.join(self.getDataDir, 'pdfs')\n  ENABLE_DEBUG_METHODS = self.enableDebug\n\n  puts \"DATA_DIR = #{self.getDataDir}\"\n  puts \"DOCUMENTS_BASEPATH = #{DOCUMENTS_BASEPATH}\"\n  puts \"ENABLE_DEBUG_METHODS = #{ENABLE_DEBUG_METHODS}\"\n\n  ########## Initialize environment, using helpers ##########\n  FileUtils.mkdir_p(DOCUMENTS_BASEPATH)\nend\n"
  },
  {
    "path": "webapp/tabula_web.rb",
    "content": "# -*- coding: utf-8 -*-\nrequire 'cuba'\nrequire 'cuba/render'\n\nrequire 'digest/sha1'\nrequire 'json'\nrequire 'csv'\nrequire 'tempfile'\nrequire 'fileutils'\nrequire 'securerandom'\n\nrequire_relative '../lib/tabula_java_wrapper.rb'\njava_import 'java.io.ByteArrayOutputStream'\njava_import 'java.util.zip.ZipEntry'\njava_import 'java.util.zip.ZipOutputStream'\n\nrequire_relative './tabula_settings.rb'\n\nbegin\n  require_relative './tabula_version.rb'\nrescue LoadError\n  $TABULA_VERSION = \"rev#{`git rev-list --max-count=1 HEAD`.strip}\"\nend\n\nrequire_relative '../lib/tabula_workspace.rb'\nrequire_relative '../lib/tabula_job_executor/executor.rb'\nrequire_relative '../lib/tabula_job_executor/jobs/generate_document_data.rb'\nrequire_relative '../lib/tabula_job_executor/jobs/generate_thumbnails.rb'\nrequire_relative '../lib/tabula_job_executor/jobs/detect_tables.rb'\n\n\ndef is_valid_pdf?(path)\n  File.open(path, 'r') { |f| f.read(4) } == '%PDF'\nend\n\n\nSTATIC_ROOT = if defined?($servlet_context)\n                File.join($servlet_context.getRealPath('/'), 'WEB-INF/webapp/static')\n              else\n                File.join(File.dirname(__FILE__), 'static')\n              end\n\nCuba.plugin Cuba::Render\nCuba.settings[:render].store(:views, File.expand_path(\"views\", File.dirname(__FILE__)))\nCuba.use Rack::MethodOverride\nCuba.use Rack::Static, root: STATIC_ROOT, urls: [\"/css\",\"/js\", \"/img\", \"/swf\", \"/fonts\"]\nCuba.use Rack::ContentLength\nCuba.use Rack::Reloader\n\n\ndef upload(file)\n  original_filename = file[:filename]\n  file_id = Digest::SHA1.hexdigest(Time.now.to_s + original_filename) # just SHA1 of time isn't unique with multiple uploads\n  file_path = File.join(TabulaSettings::DOCUMENTS_BASEPATH, file_id)\n\n  begin\n    Tabula::Workspace.instance.move_file(file[:tempfile].path, file_id, 'document.pdf')\n  rescue Errno::EACCES\n    # Windows doesn't like tempfiles to be moved\n\tTabula::Workspace.instance.copy_file(file[:tempfile].path, file_id, 'document.pdf')\n  end\n\n  filepath = Tabula::Workspace.instance.get_document_path(file_id)\n  job_batch = SecureRandom.uuid\n  thumbnail_sizes =  [800]\n\n  GenerateDocumentDataJob.create(:filepath => filepath,\n                                 :original_filename => original_filename,\n                                 :id => file_id,\n                                 :thumbnail_sizes => thumbnail_sizes,\n                                 :batch => job_batch)\n\n  DetectTablesJob.create(:filepath => filepath,\n                         :id => file_id,\n                         :batch => job_batch)\n\n  GenerateThumbnailJob.create(:file_id => file_id,\n                              :filepath => filepath,\n                              :output_dir => file_path,\n                              :thumbnail_sizes => thumbnail_sizes,\n                              :batch => job_batch)\n  return [job_batch, file_id]\nend\n\nclass InvalidTemplateError < StandardError; end\nTEMPLATE_REQUIRED_KEYS = [\"page\", \"extraction_method\", \"x1\", \"x2\", \"y1\", \"y2\", \"width\", \"height\"]\ndef upload_template(template_file)\n  template_name = template_file[:filename].gsub(/\\.json$/, \"\").gsub(/\\.tabula-template/, \"\")\n  template_id = Digest::SHA1.hexdigest(Time.now.to_s + template_name) # just SHA1 of time isn't unique with multiple uploads\n  template_filename = template_id + \".tabula-template.json\"\n\n  # validate the uploaded template, since it really could be anything.\n  template_json = open(template_file[:tempfile].path, 'r'){|f| f.read }\n  begin\n    template_data = JSON.parse(template_json)\n  rescue JSON::ParserError => e\n    raise InvalidTemplateError.new(\"template is invalid json: #{e}\")\n  end\n\n  raise InvalidTemplateError.new(\"template is invalid, must be an array of selection objects\") unless template_data.is_a?(Array)\n  raise InvalidTemplateError.new(\"template is invalid; a selection object is invalid\") unless template_data.all?{|sel| TEMPLATE_REQUIRED_KEYS.all?{|k| sel.has_key?(k)} }\n\n  page_count = template_data.map{|sel| sel[\"page\"]}.uniq.size\n  selection_count = template_data.size\n\n  # write to file and to workspace\n  Tabula::Workspace.instance.add_template({ \"id\" => template_id,\n                                            \"template\" => template_data,\n                                            \"name\" => template_name,\n                                            \"page_count\" => page_count,\n                                            \"time\" => Time.now.to_i,\n                                            \"selection_count\" => selection_count})\n  return template_id\nend\n\nCuba.define do\n  if TabulaSettings::ENABLE_DEBUG_METHODS\n    require_relative './tabula_debug.rb'\n    on 'debug' do\n      run TabulaDebug\n    end\n  end\n\n\n  on 'queue' do\n    require_relative './tabula_job_progress.rb'\n    run TabulaJobProgress\n  end\n\n  on \"templates\" do\n    # GET  /books/ .... collection.fetch();\n    # POST /books/ .... collection.create();\n    # GET  /books/1 ... model.fetch();\n    # PUT  /books/1 ... model.save();\n    # DEL  /books/1 ... model.destroy();\n\n    on root do\n      # list them all\n      on get do\n        res.status = 200\n        res['Content-Type'] = 'application/json'\n        res.write(JSON.dump(Tabula::Workspace.instance.list_templates))\n      end\n\n      # create a template from the GUI\n      on post do\n        template_info = JSON.parse(req.params[\"model\"])\n        template_name = template_info[\"name\"] || \"Unnamed Template #{Time.now.to_s}\"\n        template_id = Digest::SHA1.hexdigest(Time.now.to_s + template_name) # just SHA1 of time isn't unique with multiple uploads\n        template_filename = template_id + \".tabula-template.json\"\n        file_path = File.join(TabulaSettings::DOCUMENTS_BASEPATH, \"..\", \"templates\")\n        # write to file\n        FileUtils.mkdir_p(file_path)\n        open(File.join(file_path, template_filename), 'w'){|f| f << JSON.dump(template_info[\"template\"])}\n        page_count = template_info.has_key?(\"page_count\") ? template_info[\"page_count\"] : template_info[\"template\"].map{|f| f[\"page\"]}.uniq.count\n        selection_count = template_info.has_key?(\"selection_count\") ? template_info[\"selection_count\"] :  template_info[\"template\"].count\n        Tabula::Workspace.instance.add_template({\n                                                  \"id\" => template_id,\n                                                  \"name\" => template_name,\n                                                  \"page_count\" => page_count,\n                                                  \"time\" => Time.now.to_i,\n                                                  \"selection_count\" => selection_count,\n                                                  \"template\" => template_info[\"template\"]\n                                                })\n        res.status = 200\n        res['Content-Type'] = 'application/json'\n        res.write(JSON.dump({template_id: template_id}))\n      end\n    end\n\n    # upload a template from disk\n    on 'upload.json' do\n      if req.params['file']\n        template_ids = [upload_template(req.params['file'])]\n      elsif req.params['files']\n        template_ids = req.params['files'].map{|f| upload_template(f)}\n      end\n      res.status = 200\n      res['Content-Type'] = 'application/json'\n      res.write(JSON.dump({template_ids: template_ids}))\n    end\n\n    on \":template_id.json\" do |template_id|\n      on get do\n        template_name = Tabula::Workspace.instance.get_template_metadata(template_id)[\"name\"] # TODO\n        res['Content-Type'] = 'application/json'\n        res['Content-Disposition'] = \"attachment; filename=\\\"#{template_name}.tabula-template.json\\\"\"\n        template_body = Tabula::Workspace.instance.get_template_body(template_id)\n        res.status = 200\n        res.write template_body\n      end\n    end\n    on \":template_id\" do |template_id|\n      on get do\n        template_metadata = Tabula::Workspace.instance.get_template_metadata(template_id) # TODO\n        template_name = template_metadata[\"name\"]\n        template_body = Tabula::Workspace.instance.get_template_body(template_id)\n        template_metadata[\"selections\"] = JSON.parse template_body\n        res.status = 200\n        res['Content-Type'] = 'application/json'\n        res.write JSON.dump(template_metadata)\n      end\n      on put do\n        old_metadata = Tabula::Workspace.instance.get_template_metadata(template_id) # TODO\n        new_metadata = old_metadata.merge(JSON.parse(req.params[\"model\"]))\n        Tabula::Workspace.instance.replace_template_metadata(template_id, new_metadata)\n        res.status = 200\n        res['Content-Type'] = 'application/json'\n        res.write(JSON.dump({template_id: template_id}))\n      end\n      on delete do\n        Tabula::Workspace.instance.delete_template(template_id)\n        res.status = 200\n        res.write ''\n      end\n    end\n  end\n\n  on delete do\n\n    on 'pdf/:file_id/page/:page_number' do |file_id, page_number|\n      index = Tabula::Workspace.instance.get_document_pages(file_id)\n      index.find { |p| p['number'] == page_number.to_i }['deleted'] = true\n      File.open(index_fname, 'w') { |f| f.write JSON.generate(index) }\n      res.write '' # Firefox complains about an empty response without this.\n    end\n\n    # delete an uploaded file\n    on 'pdf/:file_id' do |file_id|\n      Tabula::Workspace.instance.delete_document(file_id)\n      res.write '' # Firefox complains about an empty response without this.\n    end\n\n  end\n\n  on put do\n    on 'pdf/:file_id/page/:page_number' do |file_id, page_number|\n      # nothing yet\n    end\n  end\n\n\n  on get do\n    on 'pdfs' do\n      run Rack::File.new(TabulaSettings::DOCUMENTS_BASEPATH)\n    end\n\n    on 'documents' do\n      res.status = 200\n      res['Content-Type'] = 'application/json'\n      res.write(JSON.dump(Tabula::Workspace.instance.list_documents))\n    end\n\n    on 'settings' do\n      res.write JSON.dump({\n        api_version: $TABULA_VERSION,\n        disable_version_check: TabulaSettings::disableVersionCheck(),\n        disable_notifications: TabulaSettings::disableNotifications(),\n      })\n    end\n\n    on 'pdf/:file_id/metadata.json' do |file_id|\n      res['Content-Type'] = 'application/json'\n      res.write Tabula::Workspace.instance.get_document_metadata(file_id).to_json\n    end\n\n    [root, \"about\", \"pdf/:file_id\", \"help\", \"mytemplates\"].each do |paths_to_single_page_app|\n      on paths_to_single_page_app do\n        index = File.read(\"webapp/index.html\")\n        if ROOT_URI != ''\n          index.sub!(\"<base href=\\\"/\\\">\", \"<base href=\\\"#{ROOT_URI}\\\">\")\n        end\n        res.write index\n      end\n    end\n\n  end # /get\n\n  on post do\n    on 'upload.json' do\n      # Make sure this is a PDF, before doing anything\n\n      if req.params['file'] # single upload mode. this should be deleting once if decide to enable multiple upload for realzies\n        job_batch, file_id = *upload(req.params['file'])\n        unless is_valid_pdf?(req.params['file'][:tempfile].path)\n          res.status = 400\n          res.write(JSON.dump({\n            :success => false,\n            :filename => req.params['file'][:filename],\n            # :file_id => file_id,\n            # :upload_id => job_batch,\n            :error => \"Sorry, the file you uploaded was not detected as a PDF. You must upload a PDF file. Please try again.\"\n            }))\n          next # halt this handler\n        end\n\n        res.write(JSON.dump([{\n            :success => true,\n            :file_id => file_id,\n            :upload_id => job_batch\n        }]))\n      elsif req.params['files']\n        statuses = req.params['files'].map do |file|\n          if is_valid_pdf?(file[:tempfile].path)\n            job_batch, file_id = *upload(file)\n            {\n              :filename => file[:filename],\n              :success => true,\n              :file_id => file_id,\n              :upload_id => job_batch\n            }\n          else\n            {\n              :filename => file[:filename],\n              :success => false,\n              :file_id => file_id,\n              :upload_id => job_batch,\n              :error => \"Sorry, the file you uploaded was not detected as a PDF. You must upload a PDF file. Please try again.\"\n            }\n            # next # halt this handler\n          end\n        end\n        # if they all fail, return 400...\n        res.status = 400 if(statuses.find{|a| a[:success] }.empty? )\n        res.write(JSON.dump(statuses))\n      else\n        STDOUT.puts req.params.keys.inspect\n      end\n    end\n\n    on \"pdf/:file_id/data\" do |file_id|\n      pdf_path = Tabula::Workspace.instance.get_document_path(file_id)\n\n      coords = JSON.load(req.params['coords'])\n      coords.sort_by! do |coord_set|\n        [\n         coord_set['page'],\n         [coord_set['y1'], coord_set['y2']].min.to_i / 10,\n         [coord_set['x1'], coord_set['x2']].min\n        ]\n      end\n\n      tables = Tabula.extract_tables(pdf_path, coords)\n\n      filename =  if req.params['new_filename'] && req.params['new_filename'].strip.size\n                    basename = File.basename(req.params['new_filename'], File.extname(req.params['new_filename']))\n                    \"tabula-#{basename}\"\n                  else\n                    \"tabula-#{file_id}\"\n                  end\n\n      case req.params['format']\n      when 'csv'\n        res['Content-Type'] = 'text/csv'\n        res['Content-Disposition'] = \"attachment; filename=\\\"#{filename}.csv\\\"\"\n        tables.each do |table|\n          res.write table.to_csv\n        end\n      when 'tsv'\n        res['Content-Type'] = 'text/tab-separated-values'\n        res['Content-Disposition'] = \"attachment; filename=\\\"#{filename}.tsv\\\"\"\n        tables.each do |table|\n          res.write table.to_tsv\n        end\n      when 'zip'\n        res['Content-Disposition'] = \"attachment; filename=\\\"#{filename}.zip\\\"\"\n\n        # I hate Java, Ruby, JRuby, Zip files, C, umm, computers, Linux, GNU,\n        # parrots-as-gifts, improper climate-control settings, tar, gunzip,\n        # streams, computers, did I say that already? ugh.\n        baos = ByteArrayOutputStream.new;\n        zos = ZipOutputStream.new baos\n\n        tables.each_with_index do |table, index|\n          # via https://stackoverflow.com/questions/23612864/create-a-zip-file-in-memory\n          # /* File is not on the disk, test.txt indicates\n          #    only the file name to be put into the zip */\n          entry = ZipEntry.new(\"#{filename}-#{index}.csv\")\n\n          # /* use more Entries to add more files\n          #    and use closeEntry() to close each file entry */\n          zos.putNextEntry(entry)\n          zos.write(table.to_csv.to_java_bytes) # lol java BITES...\n          zos.closeEntry()\n        end\n        zos.finish\n        # you know what, I changed my mind about JRuby.\n        # this is actually way easier than it would be in MRE/CRuby.\n        # ahahaha. I get the last laugh now.\n\n        res.write String.from_java_bytes(baos.to_byte_array)\n      when 'script'\n        # Write shell script of tabula-extractor commands.  $1 takes\n        # the name of a file from the command line and passes it\n        # to tabula-extractor so the script can be reused on similar pdfs.\n        res['Content-Type'] = 'application/x-sh'\n        res['Content-Disposition'] = \"attachment; filename=\\\"#{filename}.sh\\\"\"\n        coords.each do |c|\n          extraction_method_switch = if c['extraction_method'] == \"original\"\n                                        \"--no-spreadsheet\"\n                                     elsif c['extraction_method'] == \"spreadsheet\"\n                                        \"--spreadsheet\"\n                                     else\n                                        \"\"\n                                     end\n          res.write \"java -jar tabula-java.jar #{extraction_method_switch} -a #{c['y1'].round(3)},#{c['x1'].round(3)},#{c['y2'].round(3)},#{c['x2'].round(3)} -p #{c['page']} \\\"$1\\\" \\n\"\n        end\n      when 'bbox'\n        # Write json representation of bounding boxes and pages for\n        # use in OCR and other back ends.\n        res['Content-Type'] = 'application/json'\n        res['Content-Disposition'] = \"attachment; filename=\\\"#{filename}.json\\\"\"\n        res.write coords.to_json\n      when 'json'\n        # Write json representation of bounding boxes and pages for\n        # use in OCR and other back ends.\n        res['Content-Type'] = 'application/json'\n        res['Content-Disposition'] = \"attachment; filename=\\\"#{filename}.json\\\"\"\n\n        # start JSON array\n        res.write  \"[\"\n        tables.each_with_index do |table, index|\n          res.write \", \" if index > 0\n          res.write table.to_json[0...-1] + \", \\\"spec_index\\\": #{table.spec_index}}\"\n        end\n\n        # end JSON array\n        res.write \"]\"\n     else\n        res['Content-Type'] = 'application/json'\n\n        # start JSON array\n        res.write  \"[\"\n        tables.each_with_index do |table, index|\n          res.write \", \" if index > 0\n          res.write table.to_json[0...-1] + \", \\\"spec_index\\\": #{table.spec_index}}\"\n        end\n\n        # end JSON array\n        res.write \"]\"\n      end\n    end\n  end\nend\n"
  }
]