Full Code of tabulapdf/tabula for AI

master 1b8b60fa71a6 cached
66 files
710.7 KB
197.8k tokens
164 symbols
1 requests
Download .txt
Showing preview only (739K chars total). Download the full file or copy to clipboard to get everything.
Repository: tabulapdf/tabula
Branch: master
Commit: 1b8b60fa71a6
Files: 66
Total size: 710.7 KB

Directory structure:
gitextract_p3cg83uv/

├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       └── release.yml
├── .gitignore
├── .ruby-version
├── .travis.yml
├── AUTHORS.md
├── CONTRIBUTING.md
├── Dockerfile
├── Gemfile
├── Jarfile
├── LICENSE.md
├── NOTICE.txt
├── README.md
├── Rakefile
├── build/
│   ├── appbundler-1.0.jar
│   ├── dist-LICENSE.txt
│   ├── dist-README.txt
│   └── icons/
│       └── tabula.icns
├── build.xml
├── config.rb
├── config.ru
├── docker-compose.yml
├── lib/
│   ├── tabula_java_wrapper.rb
│   ├── tabula_job_executor/
│   │   ├── executor.rb
│   │   └── jobs/
│   │       ├── detect_tables.rb
│   │       ├── generate_document_data.rb
│   │       └── generate_thumbnails.rb
│   ├── tabula_workspace.rb
│   └── thumbnail_generator.rb
└── webapp/
    ├── index.html
    ├── static/
    │   ├── css/
    │   │   ├── _bootstrap-variables.scss
    │   │   ├── selectors.css
    │   │   └── styles.css
    │   ├── js/
    │   │   ├── debug_pdf_view.js
    │   │   ├── library.js
    │   │   ├── pdf_view.js
    │   │   ├── rectangularSelector.js
    │   │   ├── resizableSelection.js
    │   │   ├── tabula.js
    │   │   ├── template_library.js
    │   │   └── vendor/
    │   │       ├── backbone-min.js
    │   │       ├── bootstrap/
    │   │       │   ├── affix.js
    │   │       │   ├── alert.js
    │   │       │   ├── button.js
    │   │       │   ├── carousel.js
    │   │       │   ├── collapse.js
    │   │       │   ├── dropdown.js
    │   │       │   ├── modal.js
    │   │       │   ├── popover.js
    │   │       │   ├── scrollspy.js
    │   │       │   ├── tab.js
    │   │       │   ├── tooltip.js
    │   │       │   └── transition.js
    │   │       ├── bootstrap.js
    │   │       ├── handlebars-v1.3.0.js
    │   │       ├── table2CSV.js
    │   │       ├── underscore-min.js
    │   │       └── upload-group.js
    │   ├── sass/
    │   │   ├── _bootstrap-variables.scss
    │   │   ├── selectors.scss
    │   │   └── styles.scss
    │   └── swf/
    │       └── ZeroClipboard.swf
    ├── tabula_debug.rb
    ├── tabula_job_progress.rb
    ├── tabula_settings.rb
    └── tabula_web.rb

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

open_collective: tabulapdf



================================================
FILE: .github/workflows/release.yml
================================================
on:
  release:
    types: [published]
permissions:
  contents: read
  packages: write
jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: docker/login-action@v2
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ github.token }}
      - uses: docker/build-push-action@v4
        with:
          push: true
          tags: |
            ghcr.io/${{ github.repository }}:${{ github.ref_name }}
            ghcr.io/${{ github.repository }}:latest


================================================
FILE: .gitignore
================================================
static/pdfs
local_settings.rb
tabula.war
.sass-cache

lib/jars/javacv*
.ruby-gemset

TEST_PDFS
.DS_Store
build/Tabula.app
build/tabula.jar
build/tabula-*.zip
build/mac
build/windows
build/tabula
launch4j/

# Based on https://github.com/github/gitignore/blob/master/Ruby.gitignore
*.gem
*.rbc
*.swp
.bundle
.config
.DS_store
coverage
InstalledFiles
lib/bundler/man
pkg
rdoc
spec/reports
test/tmp
test/version_tmp
tmp


================================================
FILE: .ruby-version
================================================
jruby-9.2.13.0


================================================
FILE: .travis.yml
================================================
sudo: false
language: ruby
dist: trusty
before_install:
  - gem update --system
  - gem install bundler
  - gem install jbundler
rvm:
  - jruby-9.1.9.0
jdk:
  - oraclejdk8
  - openjdk7
script: bundle exec jbundle install && bundle exec rake war && bundle exec rake jardist
notifications:
  email: false


================================================
FILE: AUTHORS.md
================================================
# Authors & Acknowledgments

Tabula was originally started by Manuel Aristarán in late 2012.

The PRIMARY AUTHORS are (and/or have been):

* Manuel Aristarán - MIT Media Lab (formerly La Nación, Knight-Mozilla OpenNews)
* Mike Tigas - ProPublica, Knight-Mozilla OpenNews
* Jeremy B. Merrill - The New York Times (formerly ProPublica)
* Jason Das, designer <http://jasondas.com>
* David Frackman
* Travis Swicegood - Texas Tribune

Special thanks to these organizations:

* Knight-Mozilla OpenNews <https://opennews.org/>
* ProPublica <http://propublica.org>
* La Nación <http://www.lanacion.com.ar>
* The New York Times <http://www.nytimes.com>
* Knight Lab at Northwestern University <http://knightlab.northwestern.edu/>
* The John S. and James L. Knight Foundation <http://www.knightfoundation.org/>


================================================
FILE: CONTRIBUTING.md
================================================
CONTRIBUTING
============

Tabula is an open-source project, which means it depends on volunteers to build and improve it.

Interested in helping out? We'd love to have your help!

You can help by:

- [Reporting a bug](https://github.com/tabulapdf/tabula/issues/new).
- Adding or editing documentation.
- Contributing code via a Pull Request from ideas listed in the [Enhancements](https://github.com/tabulapdf/tabula/labels/enhancement) section of the issues.
- Spreading the word about Tabula to people who might be able to benefit from using it.

Did you have a problem? Guidelines for reporting a bug
------------------------------------------------------

Did 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.

1. 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!)
2. What steps did you take? The more precise, the better.
3. 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.
4. What version of Tabula are you using? If you're using an older version, we may have solved the problem already.
5. 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.

Guidelines for contributing code
--------------------------------

If 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.

Tabula comes in a bunch of parts, all located in the [TabulaPDF Github organization](https://github.com/tabulapdf). 
 -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"
 - [tabula-java](https://github.com/tabulapdf/tabula-java/) is a pure Java port, for speed/wider usability. 

The [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.


================================================
FILE: Dockerfile
================================================
FROM jruby:9.2-jdk

RUN apt-get update -qq && apt-get install -y build-essential git \
  && apt-get clean && rm -rf /var/lib/apt/lists/*
RUN echo 'gem: --no-rdoc --no-ri' >> /.gemrc

ENV GEM_HOME /usr/local/bundle
ENV PATH $GEM_HOME/bin:$PATH
RUN gem install bundler -v '< 2' \
  && bundle config --global path "$GEM_HOME" \
  && bundle config --global bin "$GEM_HOME/bin"

# don't create ".bundle" in all our apps
ENV BUNDLE_APP_CONFIG $GEM_HOME

WORKDIR /app
EXPOSE 9292
CMD ["jruby", "-G", "-r", "jbundler", "-S", "rackup", "-o", "0.0.0.0", "config.ru"]

# these didn't work as ONBUILD, strangely. Idk why. -JBM
COPY Gemfile Gemfile.lock Jarfile Jarfile.lock ./
RUN bundle install && jruby -S jbundle install
COPY . .


================================================
FILE: Gemfile
================================================
#since war/jar bundle requires gem package; use gem-in-a-box for testing
#or execute tabula via "rackup".
#source "http://127.0.0.1:9292"

source "https://rubygems.org"
platform :jruby do
  gem "cuba", "~> 3.9.2"
  gem "rack", ">= 2.0.6"
  gem "tilt", "~> 2.0.8"

  group :development do
    gem 'jar-dependencies', '0.3.12'
    gem 'jbundler', '~> 0.9.3'
    gem "rake"
    gem "warbler", "~> 2.0.5"
    gem "jruby-jars", "9.2.0.0"
    gem "bootstrap-sass", ">= 3.4.1"
    gem "compass"
  end
end


================================================
FILE: Jarfile
================================================
jar 'technology.tabula:tabula', '1.0.4'

================================================
FILE: LICENSE.md
================================================
Copyright (C) 2012-2020 Manuel Aristarán <jazzido@jazzido.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.


================================================
FILE: NOTICE.txt
================================================
Tabula
© 2012-2020 Manuel Aristarán. Available under MIT License. See `AUTHORS.md`
and `LICENSE.md`.

This product includes software (lib/pdfbox-app-1.8.0.jar) developed at
The Apache Software Foundation (http://www.apache.org/).


================================================
FILE: README.md
================================================
**Is `tabula` an active project?**

Tabula 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.

--

**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).

---



# Tabula

[tabula `master`](https://github.com/tabulapdf/tabula/tree/master)
[![Build Status](https://travis-ci.org/tabulapdf/tabula.svg?branch=master)](https://travis-ci.org/tabulapdf/tabula)  

Tabula helps you liberate data tables trapped inside PDF files.

* [Download from the official site](http://tabula.technology/)
* [Read more about Tabula on OpenNews Source](https://source.opennews.org/en-US/articles/introducing-tabula/)
* 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.)

© 2012-2020 Manuel Aristarán. Available under MIT License. See
[`AUTHORS.md`](AUTHORS.md) and [`LICENSE.md`](LICENSE.md).

-   [Why Tabula?](#why-tabula)
-   [Using Tabula](#using-tabula)
-   [Known issues](#known-issues)
-   [Incorporating Tabula into your own
    project](#incorporating-tabula-into-your-own-project)
-   [Running Tabula from source
    (for developers)](#running-tabula-from-source-for-developers)
    -   [Building a packaged application
        version](#building-a-packaged-application-version)
-   [Contributing](#contributing)
    -   [Backers](#backers)

## Why Tabula?

If you’ve ever tried to do anything with data provided to you in PDFs, you
know how painful this is — you can’t easily copy-and-paste rows of data out
of PDF files. Tabula allows you to extract that data in CSV format, through
a simple web interface.

**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.

**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.

## Using Tabula

First, make sure you have a recent copy of Java installed. You can
[download Java here][jre_download]. Tabula requires
a Java Runtime Environment compatible with Java 7 (i.e. Java 7, 8 or higher).
If you have a problem, check [Known Issues](#knownissues) first, then [report an issue](http://www.github.com/tabulapdf/tabula/issues).

* ### Windows
  Download `tabula-win.zip` from [the download site][tabula_dl]. Unzip the whole thing
  and open the `tabula.exe` file inside. A browser should automatically open
  to http://127.0.0.1:8080/ . If not, open your web browser of choice and
  visit that link.

  To close Tabula, just go back to the console window and press "Control-C"
  (as if to copy).

* ### Mac OS X
  Download `tabula-mac.zip` from [the download site][tabula_dl]. Unzip and open
  the Tabula app inside. A browser should automatically open
  to http://127.0.0.1:8080/ . If not, open your web browser of choice and
  visit that link.

  To close Tabula, find the Tabula icon in your dock, right-click (or
  control-click) on it, and press "Quit".

  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.

* ### Linux snap
  
  Tabula is packaged as a snap package. If you have snap on your system, you can install it with

  ```bash
  sudo snap install tabula
  ```

* ### Other platforms (e.g. Linux)

  Download `tabula-jar.zip` from [the download site][tabula_dl] and unzip it
  to the directory of your choice. Open a terminal window, and `cd` to inside
  the `tabula` directory you just unzipped. Then run:

  `java -Dfile.encoding=utf-8 -Xms256M -Xmx1024M -jar tabula.jar`

  Then manually navigate your browser to http://127.0.0.1:8080/ (New in
  Tabula 1.1. To go back to the old behavior that automatically launches
  your web browser, use the `-Dtabula.openBrowser=true` option.

  Tabula binds to port 8080 by default. You can change it with the `warbler.port` option; for example, to use port 9999:

  `java -Dfile.encoding=utf-8 -Xms256M -Xmx1024M -Dwarbler.port=9999 -jar tabula.jar`

* ### [Docker Compose](https://docs.docker.com/compose/) quick start using [Amazon Correttto](https://github.com/corretto) image
  Make a new directory e.g. `tabulapdf` and enter it.
  
  `mkdir -p /opt/docker/tabulapdf`
  `cd /opt/docker/tabulapdf`
  
  Download tabula-jar package - for example version 1.2.1
  
  `wget https://github.com/tabulapdf/tabula/releases/download/v1.2.1/tabula-jar-1.2.1.zip`
  
  verify checksum (compare output with the release page)

  `sha256sum tabula-jar-1.2.1.zip`
  
  and unzip it.
  
  `unzip tabula-jar-1.2.1.zip`
  
  Place or create a `docker-compose.yml` file, adjust accordingly
  
  ```
  ### tabulapdf docker-compose.yml example ###
  services:
  tabulapdf:
    image: amazoncorretto:17
    container_name: tabulapdf-app
    command: >
      java -Dfile.encoding=utf-8 -Xms256M -Xmx1024M -Dwarbler.port=8080 -Dtabula.openBrowser=false -jar /app/tabula.jar
    volumes:
      - ./tabula:/app
    ports:
      - "8080:8080"
  ```
  
  Run the app with
  
  `docker compose up -d`
  
  The app will be exposed on port 8080 and can be easily paired with a reverse proxy e.g. traefik

If the program fails to run, double-check that you have [Java installed][jre_download]
and then try again.

[jre_download]: https://www.java.com/download/
[tabula_dl]: http://tabula.technology



## <a name="knownissues">Known issues</a>

There 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).


* <a name='legacy'>**Legacy Java Environment (SE 6) Is Required:**</a> (Mac):
  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.

* <a name='gatekeeper'>**"Tabula is damaged and can't be opened"** (Mac)</a>:
  If you’re running Mac OS X 10.8 or later, GateKeeper may prevent you from opening
  the Tabula app. Please [see this GateKeeper page][gatekeeper] for more information.

  1. Right-click on Tabula.app and select Open from the context menu.
  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.

  (If you continue to have issues, double-check the [OS X GateKeeper documentation][gatekeeper] for more information.)

[gatekeeper]: http://support.apple.com/kb/HT5290

* <a name='encoding'>**org.jruby.exceptions.RaiseException: (Encoding::CompatibilityError) incompatible character encodings:**</a> (Windows):
  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.)

  1. Open a Command Prompt
  2. type `cd` and then the path to the directory that contains `tabula.exe`, e.g. `cd C:\Users\Username\Downloads`
  3. Change that terminal's codepage to Unicode by typing: `chcp 65001`
  4. Run Tabula by typing `tabula.exe`

* <a name='portproblems'>**A browser tab opens, but something other than Tabula loads there. Or Tabula doesn't start.**</a>
  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:

  `java -Dfile.encoding=utf-8 -Xms256M -Xmx1024M -Dwarbler.port=9999 -jar tabula.jar`

## Incorporating Tabula into your own project

Tabula 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.

### Bindings:

Tabula 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.

 - [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).
 - [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).
 - [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).
 - [tabula-extractor](https://github.com/tabulapdf/tabula-extractor/) *DEPRECATED* - Provides JRuby bindings for tabula-java




## Running Tabula from source (for developers)

1. Download JRuby. You can install it from its website, or using tools like
   `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).

2. Download Tabula and install the Ruby dependencies. (Note: if using `rvm` or
   `rbenv`, ensure that JRuby is being used.

    ~~~
    git clone git://github.com/tabulapdf/tabula.git
    cd tabula

    gem install bundler -v 1.17.3
    bundle install
    jruby -S jbundle install
    ~~~

**Then, start the development server:**

    jruby -G -r jbundler -S rackup

(If you get encoding errors, set the `JAVA_OPTS` environment variable to `-Dfile.encoding=utf-8`)

The site instance should now be viewable at http://127.0.0.1:9292/ .

You can a couple some options when executing the server in this manner:

    TABULA_DATA_DIR="/tmp/tabula" \
    TABULA_DEBUG=1 \
    jruby -G -r jbundler -S rackup

* `TABULA_DATA_DIR` controls where uploaded data for Tabula is stored. By default,
  data is stored in the OS-dependent application data directory for the current
  user. (similar to: `C:\Users\foo\AppData\Roaming\Tabula` on Windows,
  `~/Library/Application Support/Tabula` on Mac, `~/.tabula` on Linux/UNIX)
* `TABULA_DEBUG` prints out extra status data when PDF files are being processed.
   (`false` by default.)

**Alternatively, running the server as a JAR file**

Testing in this manner will be closer to testing the "packaged application"
version of the app.

    jruby -G -S rake war
    java -Dfile.encoding=utf-8 -Xms256M -Xmx1024M -jar build/tabula.jar


If 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:

    mvn install:install-file -Dfile=target/tabula-<version>-SNAPSHOT.jar -DgroupId=technology.tabula -DartifactId=tabula -Dversion=<version>-SNAPSHOT -Dpackaging=jar -DpomFile=pom.xml

Then, adjust the `Jarfile` accordingly.

### Building a packaged application version

After performing the above steps ("Running Tabula from source"), you can compile
Tabula into a standalone application:

**Mac OS X**

If you wish to share Tabula with other machines, you will need a codesigning certificate.
Our distribution of Tabula uses a self-signed certificate, as noted above. See
[this section of build.xml][buildxml_cert] for details. If you will only be running Tabula
on the machine you are building it on, you may remove this entire <exec> block (lines 44-53).

To compile the app:

    WEBSERVER_VERSION=9.4.31.v20200723 MAVEN_REPO=https://repo1.maven.org/maven2 rake macosx

This will result in a portable "tabula_mac.zip" archive (inside the `build` directory)
for Mac OS X users.

Note that the Mac version bundles Java with the Tabula app.
This results in a 98MB zip file, versus the 30MB zip file for other platforms,
but allows users to run Tabula without having to worry about [Java version
incompatibilities](https://github.com/tabulapdf/tabula/issues/237).

[buildxml_cert]: https://github.com/tabulapdf/tabula/blob/master/build.xml#L44-53

**Windows**

You can build .exe files for the Windows target on any platform.

Download a [3.1.X (beta) copy of Launch4J][launch4j].

Unzip it into the Tabula repo so that "launch4j" (with subdirectories "bin", etc.)
is in the repository root.

(If you're building on a 64bit Linux, you may need to install 32bit libs like, in Ubuntu `sudo apt-get install lib32z1 lib32ncurses5`)


Then:

    WEBSERVER_VERSION=9.4.31.v20200723 MAVEN_REPO=https://repo1.maven.org/maven2 rake windows

This will result in a portable "tabula_win.zip" archive (inside the `build` directory)
for Mac OS X users.

---

If you have issues, you can try building manually. (These commands are for
OS X/Linux and may need to be adjusted for Windows users.)

    # (from the root directory of the repo)
    WEBSERVER_VERSION=9.4.31.v20200723 MAVEN_REPO=https://repo1.maven.org/maven2 rake war
    cd launch4j
    ant -f ../build.xml windows

A "tabula.exe" file will be generated in "build/windows". To run, the exe file
needs "tabula.jar" (contained in "build") in the same directory. You can create a
.zip archive by doing:

    # (from the root directory of the repo)
    cd build/windows
    mkdir tabula
    cp tabula.exe ./tabula/
    cp ../tabula.jar ./tabula/
    zip -r9 tabula_win.zip tabula
    rm -fr tabula

[launch4j]: http://sourceforge.net/projects/launch4j/files/launch4j-3/3.1.0-beta1/

## Contributing

Interested in helping out? We'd love to have your help!

You can help by:

- [Reporting a bug](https://github.com/tabulapdf/tabula/issues).
- Adding or editing documentation.
- 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)
- Spreading the word about Tabula to people who might be able to benefit from using it.

### Backers

You 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.

Tabula 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!

<a href="https://opencollective.com/tabulapdf/backer/0/website" target="_blank"><img src="https://opencollective.com/tabulapdf/backer/0/avatar"></a>
<a href="https://opencollective.com/tabulapdf/backer/1/website" target="_blank"><img src="https://opencollective.com/tabulapdf/backer/1/avatar"></a>
<a href="https://opencollective.com/tabulapdf/backer/2/website" target="_blank"><img src="https://opencollective.com/tabulapdf/backer/2/avatar"></a>
<a href="https://opencollective.com/tabulapdf/backer/3/website" target="_blank"><img src="https://opencollective.com/tabulapdf/backer/3/avatar"></a>
<a href="https://opencollective.com/tabulapdf/backer/4/website" target="_blank"><img src="https://opencollective.com/tabulapdf/backer/4/avatar"></a>
<a href="https://opencollective.com/tabulapdf/backer/5/website" target="_blank"><img src="https://opencollective.com/tabulapdf/backer/5/avatar"></a>

<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>
<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>

More acknowledgments can be found in [`AUTHORS.md`](AUTHORS.md).


================================================
FILE: Rakefile
================================================
require 'fileutils'
require 'warbler'

########## java jar compilation ##########

Warbler::Task.new("war",
  Warbler::Config.new { |config|
    config.features = %w(executable)
    config.jar_name = 'build/tabula'
    config.jar_extension = 'jar'
    config.webserver = "jetty"
    config.webxml.jruby.compat.version = "1.9"
    config.webxml.jruby.rack.logging = "stderr"
    config.dirs = ['lib', 'webapp']
    config.override_gem_home = false
    config.init_contents << StringIO.new("\nGem.clear_paths\nGem.path\n\n")
  }
)

# version we're building
def build_version
  ENV['TABULA_VERSION'] || "rev#{`git rev-list --max-count=1 HEAD`.strip}"
end

def invoke_ant(*args)
  IO.popen("ant #{args.join(' ')}") { |f|
    yield f
  }
end

########## distribution bundles ##########
task :create_version_file do |t|
  puts "Creating version file (#{build_version})..."
  tabula_dir = File.expand_path(File.dirname(__FILE__))
  rb_file = <<-eos
    $TABULA_VERSION = "#{build_version}"
  eos
  File.open(File.join(tabula_dir, 'webapp', 'tabula_version.rb'), 'wb') do |f|
    f.write rb_file
  end
end

task :delete_version_file do |t|
  tabula_dir = File.expand_path(File.dirname(__FILE__))
  FileUtils.rm(File.join(tabula_dir, 'webapp', 'tabula_version.rb'))
end


task :jardist => [:create_version_file, :war] do |t|
  tabula_dir = File.expand_path(File.dirname(__FILE__))
  build_dir = File.join(tabula_dir, "build")
  dist_dir = File.join(build_dir, "jardist", "tabula")

  if File.exist?(File.join(build_dir, "jardist"))
    FileUtils.rm_rf(File.join(build_dir, "jardist"))
  end

  puts "\n======================================================"
  puts "Building jar zip file bundle..."
  puts "======================================================\n\n"

  Dir.mkdir(File.join(build_dir, "jardist"))
  Dir.mkdir(File.join(build_dir, "jardist", "tabula"))

  jar_src = File.join(build_dir, "tabula.jar")
  jar_dst = File.join(dist_dir, "tabula.jar")
  FileUtils.cp(jar_src, jar_dst)

  readme_src = File.join(build_dir, "dist-README.txt")
  readme_dst = File.join(dist_dir, "README.txt")
  FileUtils.cp(readme_src, readme_dst)

  lic_src = File.join(build_dir, "dist-LICENSE.txt")
  lic_dst = File.join(dist_dir, "LICENSE.txt")
  FileUtils.cp(lic_src, lic_dst)

  authors_src = File.join(tabula_dir, "AUTHORS.md")
  authors_dst = File.join(dist_dir, "AUTHORS.txt")
  FileUtils.cp(authors_src, authors_dst)

  cd File.join(build_dir, "jardist")
  output = File.join(build_dir, "tabula-jar-#{build_version}.zip")
  if File.exists?(output)
    File.delete(output)
  end

  IO.popen("zip -r9 #{output} tabula") { |f|
    f.each { |line| puts line }
  }
  FileUtils.rm_rf(dist_dir)
  puts "\n======================================================"
  puts "Zip file saved to #{output}"
  puts "======================================================\n\n"
end


task :macosx => [:create_version_file, :war] do |t|
  tabula_dir = File.expand_path(File.dirname(__FILE__))
  build_dir = File.join(tabula_dir, "build")
  dist_dir = File.join(build_dir, "mac", "tabula")

  cd File.join(tabula_dir)

  if File.exist?(File.join(build_dir, "mac"))
    FileUtils.rm_rf(File.join(build_dir, "mac"))
  end

  puts "\n======================================================"
  puts "Building Mac OS X app..."
  puts "======================================================\n\n"

  invoke_ant("-Dfull_version=#{build_version}", "-v", "macbundle") { |f|
    f.each { |line| puts line }
  }


  puts "\n======================================================"
  puts "Creating zip file bundle..."
  puts "======================================================\n\n"

  Dir.mkdir(dist_dir)

  app_src = File.join(build_dir, "mac", "Tabula.app")
  app_dst = File.join(dist_dir, "Tabula.app")
  FileUtils.mv(app_src, app_dst)

  readme_src = File.join(build_dir, "dist-README.txt")
  readme_dst = File.join(dist_dir, "README.txt")
  FileUtils.cp(readme_src, readme_dst)

  lic_src = File.join(build_dir, "dist-LICENSE.txt")
  lic_dst = File.join(dist_dir, "LICENSE.txt")
  FileUtils.cp(lic_src, lic_dst)

  authors_src = File.join(tabula_dir, "AUTHORS.md")
  authors_dst = File.join(dist_dir, "AUTHORS.txt")
  FileUtils.cp(authors_src, authors_dst)

  cd File.join(build_dir, "mac")
  output = File.join(build_dir, "tabula-mac-#{build_version}.zip")
  if File.exists?(output)
    File.delete(output)
  end

  IO.popen("zip -r9 #{output} tabula") { |f|
    f.each { |line| puts line }
  }
  FileUtils.rm_rf(dist_dir)
  puts "\n======================================================"
  puts "Zip file saved to #{output}"
  puts "======================================================\n\n"
end


task :windows => [:create_version_file, :war] do |t|
  tabula_dir = File.expand_path(File.dirname(__FILE__))
  build_dir = File.join(tabula_dir, "build")
  dist_dir = File.join(build_dir, "windows", "tabula")

  if File.exist?(File.join(build_dir, "windows"))
    FileUtils.rm_rf(File.join(build_dir, "windows"))
  end

  cd File.join(tabula_dir)

  puts "\n======================================================"
  puts "Building Windows executable..."
  puts "======================================================\n\n"

  # exe files REALLY need x.x.x.x otherwise the compile fails.
  if build_version.start_with?('rev')
    win_build_version = '0.0.0.0'
  else
    win_build_version = build_version
    while win_build_version.split('.').length < 4
      win_build_version = "#{win_build_version}.0"
    end
  end

  cd File.join(File.expand_path(File.dirname(__FILE__)), "launch4j")
  invoke_ant("-Dfull_version=#{win_build_version}", "-f", "../build.xml", "windows") { |f|
    f.each { |line| puts line }
  }
  puts "\n======================================================"
  puts "Creating zip file bundle..."
  puts "======================================================\n\n"

  Dir.mkdir(dist_dir)

  app_src = File.join(build_dir, "windows", "tabula.exe")
  app_dst = File.join(dist_dir, "tabula.exe")
  FileUtils.mv(app_src, app_dst)

  jar_src = File.join(build_dir, "tabula.jar")
  jar_dst = File.join(dist_dir, "tabula.jar")
  FileUtils.cp(jar_src, jar_dst)

  readme_src = File.join(build_dir, "dist-README.txt")
  readme_dst = File.join(dist_dir, "README.txt")
  FileUtils.cp(readme_src, readme_dst)

  lic_src = File.join(build_dir, "dist-LICENSE.txt")
  lic_dst = File.join(dist_dir, "LICENSE.txt")
  FileUtils.cp(lic_src, lic_dst)

  authors_src = File.join(tabula_dir, "AUTHORS.md")
  authors_dst = File.join(dist_dir, "AUTHORS.txt")
  FileUtils.cp(authors_src, authors_dst)

  cd File.join(build_dir, "windows")
  output = File.join(build_dir, "tabula-win-#{build_version}.zip")
  if File.exists?(output)
    File.delete(output)
  end

  IO.popen("zip -r9 #{output} tabula") { |f|
    f.each { |line| puts line }
  }
  FileUtils.rm_rf(dist_dir)
  puts "\n======================================================"
  puts "Zip file saved to #{output}"
  puts "======================================================\n\n"
end

task :build_all_platforms => [:create_version_file, :war] do |t|
  ['jardist', 'macosx', 'windows'].each do |platform|
    Rake::Task[platform].execute
    puts
  end
end

# delete version file after build
['jardist', 'macosx', 'windows'].each do |t|
  puts "Deleting version file."
  Rake::Task[t.intern].enhance {
    Rake::Task['delete_version_file'.intern].invoke
  }
end


================================================
FILE: build/dist-LICENSE.txt
================================================
tabula and tabula-extractor

Copyright (C) 2012-2020 Manuel Aristarán <jazzido@jazzido.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

/*****************************************************************************/
tabula-extractor -> pdfbox

This product includes software (target/pdfbox-app-1.8.0.jar) developed at
The Apache Software Foundation (http://www.apache.org/). Licensed under the
Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0).

/*****************************************************************************/
tabula-extractor -> ext/lsd.c

  LSD - Line Segment Detector on digital images

  This code is part of the following publication and was subject
  to peer review:

    "LSD: a Line Segment Detector" by Rafael Grompone von Gioi,
    Jeremie Jakubowicz, Jean-Michel Morel, and Gregory Randall,
    Image Processing On Line, 2012. DOI:10.5201/ipol.2012.gjmr-lsd
    http://dx.doi.org/10.5201/ipol.2012.gjmr-lsd

  Copyright (c) 2007-2011 rafael grompone von gioi <grompone@gmail.com>

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as
  published by the Free Software Foundation, either version 3 of the
  License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with this program. If not, see <http://www.gnu.org/licenses/>.

  Additional permission under GNU GPL version 3 section 7

  If you modify this Program, or any covered work, by linking or
  combining it with Tabula (or a modified version of that library),
  containing parts covered by the terms of "MIT License", the
  licensors of this Program grant you additional permission to convey
  the resulting work. Corresponding Source for a non-source form of
  such a combination shall include the source code for the parts of
  Tabula used as well as that of the covered work.


================================================
FILE: build/dist-README.txt
================================================
# Tabula

Tabula helps you liberate data tables trapped inside PDF files.

* The latest downloads and documentation are always available at:
  http://tabula.technology/

* Read more about Tabula on OpenNews Source:
  https://source.opennews.org/en-US/articles/introducing-tabula/

* See the GitHub project for source code, technical info, and more:
  https://github.com/tabulapdf/tabula

* Find a bug? Report it on GitHub:
  https://github.com/tabulapdf/tabula/issues

© 2012-2020 Manuel Aristarán. Available under MIT License.
See `AUTHORS.txt` and `LICENSE.txt`.

---

## Using Tabula

First, make sure you have a recent copy of Java installed. You can
download Java at https://www.java.com/download/ . Tabula requires
a Java Runtime Environment compatible with Java 6 or Java 7.

### Windows (tabula-win.zip)

Open tabula.exe and a browser should automatically open to
http://127.0.0.1:8080/ . If not, open your web browser of choice and visit
that URL.

### Mac OS X (tabula-mac.zip)

Open the Tabula app and a browser should automatically open to
http://127.0.0.1:8080/ . If not, open your web browser of choice and visit
that URL.

### JAR file for Linux/Other (tabula-jar.zip)

Open a terminal window, and `cd` to inside this `tabula` directory,
then run the following command

  java -Dfile.encoding=utf-8 -Xms256M -Xmx1024M -jar tabula.jar

Then, manually open your web browser to http://127.0.0.1:8080/ to access
the Tabula interface. Tabula binds to port 8080 by default. You can change
it with the `warbler.port` option; for example, if you want to use port 9999:

  java -Dfile.encoding=utf-8 -Xms256M -Xmx1024M -Dwarbler.port=9999 -jar tabula.jar

(You can enable the old "automatically open browser" behavior by using
the `-Dtabula.openBrowser=true` option.)


================================================
FILE: build.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project name="tabula" default="build" basedir=".">

  <property file="build.properties"/>
  <property name="build.dir" value="build"/>
  <property name="mac.dir" value="${build.dir}/mac" />
  <property name="windows.dir" value="${build.dir}/windows" />
  <property name="full_version" value="1.2.1.18052200"/>
  <property name="launch4j.dir" location="${build.dir}/../launch4j"  />
  <property name="launch4j.bindir" location="${build.dir}/../launch4j/bin" />

  <target name="check-jar-exists">
    <available file="${build.dir}/tabula.jar" property="jar.exists"/>
  </target>

  <target name="macbundle" depends="check-jar-exists" if="jar.exists">
    <mkdir dir="${mac.dir}"/>

    <!-- this must be a real JDK -->
    <property name="java_home" value="/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home"/>

    <taskdef
        name="bundleapp"
        classname="com.oracle.appbundler.AppBundlerTask"
        classpath="${build.dir}/appbundler-1.0.jar"
        />

    <bundleapp
        outputdirectory="${build.dir}/mac"
        name="Tabula"
        displayname="Tabula"
        identifier="org.nerdpower.tabula.Tabula"
        icon="${build.dir}/icons/tabula.icns"
        shortversion="${full_version}"
        mainclassname="WarMain"
      >
        <runtime dir="${java_home}" />
        <classpath file="${build.dir}/tabula.jar" />
        <option value="-Dapple.laf.useScreenMenuBar=true"/>
        <option value="-Dwarbler.port=8080"/>
        <option value="-Dtabula.openBrowser=true"/>
    </bundleapp>
    <!--
    To allow OSX to use this, you'll need to code sign.
    Generate a self-signed "Code Signing" certificate[1], then enter
    it in the -s option here and edit below section. Users can then
    right-click or Control-click the app and "Open" and then tell OS X to
    open anyway[2].
      [1]: http://support.apple.com/kb/PH7173
      [2]: http://support.apple.com/kb/HT5290

    For production builds, you can get rid of "Unidentified Developer"
    warnings by having a Mac Developer Account and a cert from[3]. Then
    change -s option to something like 'Developer ID Application: Mike Tigas (68QUP6KP2C)',
    based on your Developer Account & cert.
      [3]: https://developer.apple.com/account/mac/certificate/certificateList.action
    -->
    <exec executable="codesign" os="Mac OS X">
      <arg line="-f -s 'Developer ID Application: Mike Tigas (68QUP6KP2C)' --deep ${build.dir}/mac/Tabula.app" />
      <!-- <arg line="-f -s 'Tabula' ${build.dir}/mac/Tabula.app" /> -->
    </exec>
  </target>

  <target name="windows" depends="check-jar-exists" if="jar.exists">
    <mkdir dir="${windows.dir}"/>
    <taskdef
        name="launch4j"
        classname="net.sf.launch4j.ant.Launch4jTask"
        classpath="${launch4j.dir}/launch4j.jar:${launch4j.dir}/lib/xstream.jar"
        />
    <launch4j bindir="${launch4j.bindir}">
      <config
          headerType="console"
          outfile="${windows.dir}/tabula.exe"
          jarPath="tabula.jar"
          dontWrapJar="true"
          icon="${build.dir}/icons/tabula.ico">
        <classPath mainClass="WarMain">
          <cp>tabula.jar</cp>
        </classPath>
        <jre minVersion="1.6.0" jdkPreference="preferJre" initialHeapSize="256" maxHeapSize="1024">
          <opt>-Dfile.encoding=utf-8</opt>
          <opt>-Dwarbler.port=8080</opt>
          <opt>-Dtabula.openBrowser=true</opt>
        </jre>
        <versionInfo
            fileVersion="${full_version}"
            txtFileVersion="${full_version}"
            fileDescription="tabula"
            copyright="© 2012-2020 Manuel Aristarán"
            productVersion="${full_version}"
            txtProductVersion="${full_version}"
            productName="Tabula"
            companyName="Tabula Team"
            internalName="tabula"
            originalFilename="tabula.exe"
            />
      </config>
    </launch4j>
  </target>
</project>


================================================
FILE: config.rb
================================================
require 'compass/import-once/activate'
# Require any additional compass plugins here.
require 'bootstrap-sass'
# Set this to the root of your project when deployed:
http_path = "webapp/"
css_dir = "webapp/static/css"
sass_dir = "webapp/static/sass"
images_dir = "webapp/static/img"
javascripts_dir = "webapp/static/js"

# You can select your preferred output style here (can be overridden via the command line):
# output_style = :expanded or :nested or :compact or :compressed

# To enable relative paths to assets via compass helper functions. Uncomment:
# relative_assets = true

# To disable debugging comments that display the original location of your selectors. Uncomment:
line_comments = false


# If you prefer the indented syntax, you might want to regenerate this
# project again passing --syntax sass, or you can uncomment this:
# preferred_syntax = :sass
# and then run:
# sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass


================================================
FILE: config.ru
================================================
# encoding: UTF-8
require 'rubygems'
require 'bundler'
Bundler.require

# Disable LittleCMS when running in JVM >= 1.8
# https://pdfbox.apache.org/2.0/getting-started.html
jvmajor, jvminor = java.lang.System.getProperty('java.specification.version').split('.')
if !jvminor.nil? && jvminor.to_i >= 8
  java.lang.System.setProperty("sun.java2d.cmm", "sun.java2d.cmm.kcms.KcmsServiceProvider")
end

require_relative './webapp/tabula_settings.rb'
require_relative './webapp/tabula_web.rb'

potential_root_uri_without_slashes = (defined?($servlet_context) ? $servlet_context.getContextPath : ENV["ROOT_URI"])

if potential_root_uri_without_slashes.nil? || potential_root_uri_without_slashes == ''
  ROOT_URI = '/'
else
  ROOT_URI = (potential_root_uri_without_slashes[0] == "/" ? '' : '/') + potential_root_uri_without_slashes +  (potential_root_uri_without_slashes[-1] == "/" ? '' : '/')
end

puts "running under #{ROOT_URI} as root URI" 


map ROOT_URI do 
  run Cuba
end

if "#{$PROGRAM_NAME}".include?("tabula.jar")
  # only do this if running as jar or app. (if "rackup", we don't
  # actually use 8080 by default.)

  require 'java'

  # don't do "java_import java.net.URI" -- it conflicts with Ruby URI and
  # makes Cuba/Rack really really upset. just call "java.*" classes
  # directly.
  port = java.lang.Integer.getInteger('warbler.port', 8080)
  url = "http://127.0.0.1:#{port}"

  puts "============================================================"
  puts url
  puts "============================================================"

  # Open browser after slight delay. (The server may take a while to actually
  # serve HTTP, so we are trying to avoid a "Could Not Connect To Server".)
  uri = java.net.URI.new(url)
  sleep 0.5

  puts "should we open browser?"
  puts "java.lang.Boolean.getBoolean('tabula.openBrowser'): #{java.lang.Boolean.getBoolean('tabula.openBrowser')}"
  have_desktop = false
  if java.lang.Boolean.getBoolean('tabula.openBrowser')
    puts "java.awt.Desktop.isDesktopSupported: #{java.awt.Desktop.isDesktopSupported}"
    if java.awt.Desktop.isDesktopSupported
      begin
        desktop = java.awt.Desktop.getDesktop()
      rescue
        puts "java.awt.Desktop.getDesktop(): no"
        desktop = nil
      else
        puts "java.awt.Desktop.getDesktop(): yes"
        have_desktop = true
      end
    end
  end

  # if running as a jar or app, automatically open the user's web browser if
  # the system supports it.
  if have_desktop
    puts "\n======================================================"
    puts "Launching web browser to #{url}\n\n"

    begin
      desktop.browse(uri)
    rescue
      puts "Unable to launch your web browser, you will have to"
      puts "manually open it to the above URL."
    else
      puts "If it does not open in 10 seconds, you may manually open"
      puts "a web browser to the above URL."
    end

    puts "When you're done using the Tabula interface, you may"
    puts "return to this window and press \"Control-C\" to close it."
    puts "======================================================\n\n"
  else
    puts "\n======================================================"
    puts "Server now listening at: #{url}\n\n"
    puts "You may now open a web browser to the above URL."
    puts "When you're done using the Tabula interface, you may"
    puts "return to this window and press \"Control-C\" to close it."
    puts "======================================================\n\n"
  end
end


================================================
FILE: docker-compose.yml
================================================
version: '3.3'
services:
  web: &web
    build:
      context: .
    command: "jruby -G -r jbundler -S rackup -p 9292 -o 0.0.0.0 config.ru"
    volumes:
      - .:/app
      - bundle:/usr/local/bundle
    ports:
      - 9292:9292

volumes:
  bundle:


================================================
FILE: lib/tabula_java_wrapper.rb
================================================
java_import org.apache.pdfbox.pdmodel.PDDocument
java_import org.apache.pdfbox.pdmodel.encryption.StandardDecryptionMaterial

class Java::TechnologyTabula::Table
  attr_accessor :spec_index
  def to_csv
    sb = java.lang.StringBuilder.new
    Java::TechnologyTabulaWriters.CSVWriter.new.write(sb, self)
    sb.toString
  end

  def to_tsv
    sb = java.lang.StringBuilder.new
    Java::TechnologyTabulaWriters.TSVWriter.new.write(sb, self)
    sb.toString
  end

  def to_json(*a)
    sb = java.lang.StringBuilder.new
    Java::TechnologyTabulaWriters.JSONWriter.new.write(sb, self)
    sb.toString
  end
end

module Tabula

  def Tabula.extract_tables(pdf_path, specs, options={})
    options = {
      :password => '',
      :detect_ruling_lines => true,
      :vertical_rulings => [],
      :extraction_method => "guess",
    }.merge(options)

    specs.each_with_index{|spec, i| spec["spec_index"] = i }
    specs = specs.group_by { |s| s['page'] }
    pages = specs.keys.sort

    extractor = Extraction::ObjectExtractor.new(pdf_path,
                                                options[:password])

    sea = Java::TechnologyTabulaExtractors.SpreadsheetExtractionAlgorithm.new
    bea = Java::TechnologyTabulaExtractors.BasicExtractionAlgorithm.new

    Enumerator.new do |y|
      extractor.extract(pages.map { |p| p.to_java(:int) }).each do |page|
        specs[page.getPageNumber].each do |spec|
          if ["spreadsheet", "original", "basic", "stream", "lattice"].include?(spec['extraction_method'])
            use_spreadsheet_extraction_method = (spec['extraction_method'] == "spreadsheet" || spec['extraction_method'] == "lattice"  )
          else # guess
            use_spreadsheet_extraction_method = sea.isTabular(page)
          end

          area = page.getArea(spec['y1'], spec['x1'], spec['y2'], spec['x2'])

          table_extractor = use_spreadsheet_extraction_method ? sea : bea
          table_extractor.extract(area).each { |table| table.spec_index = spec["spec_index"]; y.yield table }
        end
      end;
      extractor.close!
    end

  end


  module Extraction

    def Extraction.openPDF(pdf_filename, password='')
      raise Errno::ENOENT unless File.exists?(pdf_filename)
      PDDocument.load(java.io.File.new(pdf_filename))
    end

    class ObjectExtractor < Java::TechnologyTabula.ObjectExtractor

      alias_method :close!, :close

      # TODO: the +pages+ constructor argument does not make sense
      # now that we have +extract_page+ and +extract_pages+
      def initialize(pdf_filename, pages=[1], password='', options={})
        raise Errno::ENOENT unless File.exists?(pdf_filename)
        @pdf_filename = pdf_filename
        @document = Extraction.openPDF(pdf_filename, password)

        super(@document)
      end

      def page_count
        @document.get_number_of_pages
      end

    end

    class PagesInfoExtractor < ObjectExtractor

      def pages
        Enumerator.new do |y|
          self.extract.each do |page|
            y.yield({
                      :width => page.getWidth,
                      :height => page.getHeight,
                      :number => page.getPageNumber,
                      :rotation => page.getRotation.to_i,
                      :hasText => page.hasText
                    })
            end
        end
      end
    end
  end
end


================================================
FILE: lib/tabula_job_executor/executor.rb
================================================
require 'java'
java_import java.util.concurrent.ThreadPoolExecutor
java_import java.util.concurrent.TimeUnit
java_import java.util.concurrent.LinkedBlockingQueue

require 'jruby/synchronized'

require 'securerandom'
require 'singleton'

module Tabula
  class NoTextDataException < IOError; end

  module Background

    class JobExecutor < java.util.concurrent.ThreadPoolExecutor
      include Singleton

      attr_reader :jobs, :futures_jobs

      def initialize
        @jobs = Hash.new.extend(JRuby::Synchronized)
        @futures_jobs = Hash.new.extend(JRuby::Synchronized)

        super(3, # core pool size
              5, # max pool size
              300, # keep idle threads 5 minutes
              TimeUnit::SECONDS,
              LinkedBlockingQueue.new)

        at_exit do
          self.shutdown
          self.shutdownNow
        end
      end

      def afterExecute(runnable, throwable)
        super(runnable, throwable)
        if throwable.nil? and runnable.instance_of?(Java::JavaUtilConcurrent::FutureTask)
          begin
            if runnable.isDone
              runnable.get # 'get' the Future, so it rethrows exceptions if any
            end
          rescue Java::JavaUtilConcurrent::ExecutionException => e
            throwable = e
          rescue Java::JavaUtilConcurrent::CancellationException => e
            throwable = e.getCause
          rescue Java::JavaLang::InterruptedException => e
            Java::JavaLang::Thread.currentThread.interrupt
          end
          if throwable.nil?
            # task finished OK
            @futures_jobs[runnable].completed
          else
            throwable.printStackTrace(java.lang.System.out)
            # finished with exception
            throwable.printStackTrace # XXX TODO better exception logging
            @futures_jobs[runnable].failed(throwable.toString)
          end
        end
      end

      def submit(job)
        @jobs[job.uuid] = job
        future = super(job)
        @futures_jobs[future] = job
      end

      class << self
        def get(uuid)
          instance.jobs[uuid]
        end

        def get_by_batch(uuid)
          instance.jobs.select { |k, j|
            j.options[:batch] == uuid
          }
        end
      end
    end

    class Job
      include java.util.concurrent.Callable

      attr_accessor :options, :status
      attr_reader :uuid

      def initialize(options={})
        @uuid = SecureRandom.uuid
        @status = {'num' => 0 }
        self.options = options
      end

      def [](k)
        self.options[k]
      end

      def name
        "#{self.class.name}(#{options.inspect unless options.empty?})"
      end

      def call
        self.status.merge!({ 'status' => 'working', 'started_on' => Time.now })
        perform
        @uuid
      end

      def [](k)
        options[k]
      end

      def at(num, total, *messages)
        self.status.merge!({ 'status' => 'working', 'num' => num, 'total' => total, 'messages' => messages })
      end

      def queued
        self.status.merge!({ 'status' => 'queued', 'queued_on' => Time.now })
      end

      def warn(*warnings)
        self.status.merge!({ 'warnings' => warnings })
      end

      def failed(*messages)
        self.status.merge!({ 'status' => 'failed', 'messages' => messages})
      end

      def completed
        self.status.merge!({ 'status' => 'completed', 'completed_on' => Time.now })
      end

      def pct_complete
        case status['status']
          when 'completed' then 100
          when 'queued' then 0
          else
          t = (status['total'] == 0 || status['total'].nil?) ? 1 : status['total']
          (((status['num'] || 0).to_f / t.to_f) * 100).to_i
        end
      end

      def message
        self.status['messages']
      end

      alias_method :message?, :message

      def warning
        self.status['warnings']
      end

      alias_method :warning?, :warning

      STATUSES = %w{queued working completed failed killed}.freeze
      STATUSES.each do |status|
        define_method("#{status}?") do
          self.status['status'] === status
        end
      end

      class << self
        def create(options)
          job = self.new(options)
          JobExecutor.instance.submit(job)
          job.uuid
        end
      end

    end
  end
end


if __FILE__ == $0

  class K < Tabula::Background::Job
    def perform
      options[:start].upto(options[:end]) do |i|
        puts "I'm #{@uuid}: #{i}/#{options[:end]}"
        at(i, options[:end])
        sleep 1
      end
      @uuid
    end
  end

  class J < Tabula::Background::Job
    def perform
      options[:start].upto(options[:end]) do |i|
        puts "I'm #{@uuid}: #{i}/#{options[:end]}"
        at(i, options[:end])
        raise 'caca'
        sleep 1
      end
    end
  end

  j1 = K.create(:start => 1, :end => 20)
  j2 = K.create(:start => 25, :end => 40)
  j3 = J.create(:start => 1, :end => 6)

  Thread.new do
    loop {
      puts "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"

      # puts "STATUS OF J1 IN EXECUTOR: #{Tabula::Background::JobExecutor.get(j1)}"
      # puts "STATUS OF J2 IN EXECUTOR: #{Tabula::Background::JobExecutor.get(j2)}"
      # puts "STATUS OF J3 IN EXECUTOR: #{Tabula::Background::JobExecutor.get(j3)}"
      puts Tabula::Background::JobExecutor.instance.futures_jobs.inspect
      sleep 1
    }
  end
end


================================================
FILE: lib/tabula_job_executor/jobs/detect_tables.rb
================================================
require 'java'

require_relative '../executor.rb'

class DetectTablesJob < Tabula::Background::Job
  include Observable
  def perform
    filepath = options[:filepath]
    document_id = options[:id]

    page_areas_by_page = []

    begin
      extractor = Tabula::Extraction::ObjectExtractor.new(filepath, :all)
      page_count = extractor.page_count
      nda = Java::TechnologyTabulaDetectors::NurminenDetectionAlgorithm.new
      extractor.extract.each do |page|
        page_index = page.getPageNumber

        at( (page_count + page_index) / 2, page_count, "auto-detecting tables...") #starting at 50%...
        changed

        areas = nda.detect(page)
        page_areas_by_page << areas.map { |rect|
          [ rect.getLeft,
            rect.getTop,
            rect.getWidth,
            rect.getHeight ]
        }
      end

    rescue Java::JavaLang::Exception => e
      warn("Table auto-detect failed. You may need to select tables manually.")
    ensure
      extractor.close!
    end

    Tabula::Workspace.instance.add_file(page_areas_by_page.to_json, document_id, 'tables.json')

    at(100, 100, "complete")
    return nil
  end
end


================================================
FILE: lib/tabula_job_executor/jobs/generate_document_data.rb
================================================
require 'json'
require 'jruby/synchronized'

require_relative '../executor.rb'

class GenerateDocumentDataJob < Tabula::Background::Job
  include JRuby::Synchronized

  # args: (:filename, :id)
  def perform

    filepath = options[:filepath]
    original_filename = options[:original_filename]
    id = options[:id]

    # return some status to browser
    at(1, 100, "opening workspace...")

    doc = { 'original_filename' => original_filename,
            'id' => id,
            'time' => Time.now.to_i,
            'page_count' => '?',
            'size' => File.size(filepath),
            'thumbnail_sizes' => options[:thumbnail_sizes]
          }
    at(5, 100, "analyzing PDF text...")

    extractor = Tabula::Extraction::PagesInfoExtractor.new(filepath)
    page_data = extractor.pages.to_a
    doc['page_count'] = page_data.size
    unless page_data.any? { |pd| pd[:hasText] }
      at(0, 100, "No text data found")
      raise Tabula::NoTextDataException, "no text data found"
    end

    Tabula::Workspace.instance.add_document(doc, page_data)
    at(100, 100, "complete")
    extractor.close!
    return nil
  end
end


================================================
FILE: lib/tabula_job_executor/jobs/generate_thumbnails.rb
================================================
require_relative '../executor.rb'
require_relative '../../thumbnail_generator.rb'

class GenerateThumbnailJob < Tabula::Background::Job
  # args: (:file, :output_dir, :thumbnail_sizes, :page_index_job_uuid)

  def perform

    file_id = options[:file_id]
    upload_id = self.uuid
    filepath = options[:filepath]
    output_dir = options[:output_dir]
    thumbnail_sizes = options[:thumbnail_sizes]

    generator = PDFBoxThumbnailGenerator.new(filepath, output_dir, file_id, thumbnail_sizes)
    generator.add_observer(self, :at)
    generator.generate_thumbnails!

  end
end


================================================
FILE: lib/tabula_workspace.rb
================================================
require 'jruby/synchronized'
require 'singleton'

module Tabula
  class Workspace
    include JRuby::Synchronized
    include Singleton

    STARTING_VALUE = {"pdfs" => [], "templates" => [], "version" => 2}


    def initialize(data_dir=TabulaSettings.getDataDir)
      unless File.directory?(data_dir)
        raise "DOCUMENTS_BASEPATH does not exist or is not a directory."
      end

      @data_dir = data_dir
      @workspace_path = File.join(@data_dir, "pdfs", "workspace.json")
      @workspace = STARTING_VALUE
      if !File.exists?(@workspace_path)
        FileUtils.mkdir_p(File.join(@data_dir, "pdfs"))
      end
    end

    def add_document(document, pages)
      read_workspace!
      @workspace["pdfs"].unshift(document)
      add_file(pages.to_json, document['id'], 'pages.json')
      flush_workspace!
    end

    def delete_document(document_id)
      read_workspace!
      @workspace["pdfs"].delete_if { |d| d['id'] == document_id }
      flush_workspace!

      FileUtils.rm_rf(get_document_dir(document_id))
    end

    def delete_page(document_id, page_number)
      # TODO
      raise "Not Implemented"
    end

    def get_document_metadata(document_id)
      read_workspace!
      @workspace["pdfs"].find { |d| d['id'] == document_id }
    end

    def get_document_pages(document_id)
      JSON.parse(File.join(get_document_dir(document_id), 'pages.json').read)
    end

    def get_document_path(document_id)
      File.join(get_document_dir(document_id), 'document.pdf')
    end

    def list_documents
      read_workspace!
      @workspace["pdfs"]
    end



    def get_data_dir()
      @data_dir
    end

    def add_file(contents, document_id, filename)
      p = get_document_dir(document_id)

      File.open(File.join(p, filename), 'w') do |f|
        f.write contents
      end
    end

    def move_file(path, document_id, filename)
      FileUtils.mv(path, File.join(get_document_dir(document_id), filename))
    end

	def copy_file(path, document_id, filename)
	   FileUtils.cp_r(path, File.join(get_document_dir(document_id), filename))
	end

    def list_templates
      read_workspace!
      @workspace["templates"]
    end

    def get_template_metadata(template_id)
      read_workspace!
      @workspace["templates"].find { |d| d['id'] == template_id }
    end
    def get_template_body(template_id)
      puts File.join(get_templates_dir, "#{template_id}.tabula-template.json")
      open(File.join(get_templates_dir, "#{template_id}.tabula-template.json"), 'r'){|f| f.read }
    end

    def add_template(template_metadata)
      read_workspace!

      # write template metadata to workspace
      @workspace["templates"].insert(0,{
                                      "name" => template_metadata["name"].gsub(".tabula-template.json", ""), 
                                      "selection_count" => template_metadata["selection_count"],
                                      "page_count" => template_metadata["page_count"], 
                                      "time" => template_metadata["time"], 
                                      "id" => template_metadata["id"]
                                    })
      # write template file to disk
      write_template_file(template_metadata)
      flush_workspace!
    end

    def replace_template_metadata(template_id, template_metadata)
      read_workspace!
      idx = @workspace["templates"].index{|t| t["id"] == template_id}
      @workspace["templates"][idx] = template_metadata.select{|k,_| ["name", "selection_count", "page_count", "time", "id"].include?(k) }
      flush_workspace!
    end



    def delete_template(template_id)
      read_workspace!
      @workspace["templates"].delete_if { |t| t['id'] == template_id }
      flush_workspace!
      File.delete(File.join(get_templates_dir, "#{template_id}.tabula-template.json"))
    end


    private

    def write_template_file(template_metadata)
      template_name = template_metadata["name"]
      template_id = Digest::SHA1.hexdigest(Time.now.to_s + template_name) # just SHA1 of time isn't unique with multiple uploads
      template_filename = template_id + ".tabula-template.json"
      open(File.join(get_templates_dir, template_filename), 'w'){|f| f << JSON.dump(template_metadata["template"])}
    end

    def get_templates_dir
      p = File.join(@data_dir, 'templates')
      if !File.directory?(p)
        FileUtils.mkdir_p(p)
      end
      p
    end
    def get_document_dir(document_id)
      p = File.join(@data_dir, 'pdfs', document_id)
      if !File.directory?(p)
        FileUtils.mkdir_p(p)
      end
      p
    end


    def read_workspace!
      return STARTING_VALUE unless File.exists?(@workspace_path)
      File.open(@workspace_path) do |f|
        @workspace = JSON.parse(f.read)
      end
      # what if the already-existing workspace is v1? i.e. if it's just an array?
      # then we'll make it the new kind, seamlessly.
      if @workspace.is_a? Array
        @workspace = {"pdfs" => @workspace, "templates" => [], "version" => 2}
        flush_workspace!
      end
      @workspace
    end

    def flush_workspace!
      File.open(@workspace_path, 'w') do |f|
        f.write @workspace.to_json
      end
    end
  end
end


================================================
FILE: lib/thumbnail_generator.rb
================================================
# coding: utf-8
require 'java'
require 'observer'

java_import javax.imageio.ImageIO
java_import java.awt.image.BufferedImage
java_import java.awt.Image
java_import java.io.ByteArrayOutputStream

java_import org.apache.pdfbox.pdmodel.PDDocument
java_import org.apache.pdfbox.rendering.PDFRenderer

class AbstractThumbnailGenerator
  include Observable

  def initialize(pdf_filename, output_directory, sizes=[2048, 560])
    raise Errno::ENOENT unless File.directory?(output_directory)
    raise ArgumentError if sizes.empty?
    @sizes = sizes.sort.reverse
    @output_directory = output_directory
    @pdf_filename = pdf_filename
  end

  def generate_thumbnails!
    raise 'NotImplemented'
  end
end

class PDFBoxThumbnailGenerator < AbstractThumbnailGenerator
  def initialize(pdf_filename, output_directory, document_id, sizes=[2048, 560])
    super(pdf_filename, output_directory, sizes)
    @sizes = sizes
    @pdf_document = PDDocument.load(java.io.File.new(pdf_filename))
    @document_id = document_id
  end

  def generate_thumbnails!
    total_pages = @pdf_document.getNumberOfPages
    renderer = PDFRenderer.new(@pdf_document)

    total_pages.times do |pi|
      image = renderer.renderImageWithDPI(pi, 75)
      imageWidth = image.getWidth.to_f
      imageHeight = image.getHeight.to_f

      @sizes.each do |size|
        scale = size / imageWidth
        bi = BufferedImage.new(size, (imageHeight * scale).round, image.getType)
        bi.getGraphics.drawImage(image.getScaledInstance(size, (imageHeight * scale).round, Image::SCALE_SMOOTH), 0, 0, nil)

        sio = StringIO.new
        out = sio.to_outputstream
        ImageIO.write(bi, 'png', out)
        Tabula::Workspace.instance.add_file(sio.string, @document_id, "document_#{size}_#{pi+1}.png")
      end

      changed
      notify_observers(pi+1, total_pages, "generating page thumbnails…")
    end
    @pdf_document.close
  end
end

##
# use /usr/bin/mudraw for faster thumbnail generation
# useful for hosted instances of Tabula
class MUDrawThumbnailGenerator < AbstractThumbnailGenerator

  def initialize(pdf_filename, output_directory, sizes=[2048, 560], mudraw='/usr/local/bin/mudraw')
    super(pdf_filename, output_directory, sizes)
    @mudraw = mudraw
  end

  def generate_thumbnails!
    @sizes.each_with_index do |size, i|
      out = File.join(@output_directory, "document_#{size}_%d.png")

      `#{@mudraw} -o "#{out}" -w #{size} "#{@pdf_filename}"`
      changed
      notify_observers(i+1, @sizes.length, "generating page thumbnails...")
    end
  end
end


================================================
FILE: webapp/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<!-- Tabula.api_version : ask for it on the console. -->
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">
    <link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon">
    <link rel="icon" href="img/favicon.ico" type="image/x-icon">

    <title>Tabula</title>

    <base href="/"><!-- overwritten dynamically with the value of $servlet_context.getContextPath or ENV["ROOT_URI"] -->

    <link href="css/styles.css" rel="stylesheet">

    <!-- Selector-specific CSS -->
    <link href="css/selectors.css" rel="stylesheet">

    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->

    <script type="text/javascript" src="js/vendor/jquery.min.js"></script>
    <script type="text/javascript" src="js/vendor/underscore-min.js"></script>
    <script type="text/javascript" src="js/vendor/backbone-min.js"></script>
    <script type="text/javascript" src="js/vendor/bootstrap.js"></script>
  </head>


  <body data-spy="scroll" data-target=".nav.sidebar-nav" data-offset="0">
    <div class="ribbon-wrapper-green" id="dev-mode-ribbon" style="display: none;"><div class="ribbon-green">DEV mode</div></div>

    <!-- Fixed navbar -->
    <nav class="navbar navbar-default navbar-fixed-top" role="navigation">
      <div class="container">
        <div class="navbar-header">
          <a class="navbar-brand" href="">Tabula</a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
          <ul class="nav navbar-nav navbar-left">
            <li><a id="upload-nav" href="">My Files</a></li>
            <li><a id="templates-nav" href="mytemplates">My Templates</a></li>
            <li><a id="about-nav" href="about">About</a></li>
            <li><a id="help-nav" href="help">Help</a></li>
            <li><a href="https://github.com/tabulapdf/tabula" target="_blank">Source Code</a></li>
          </ul>
          <ul class="nav navbar-nav navbar-right">
            <li><a target="_blank" href="https://opencollective.com/tabulapdf">Support Tabula on OpenCollective!</a></li>
          </ul>
        </div><!--/.nav-collapse -->
      </div>
    </nav>




    <div id="tabula-app"> <!-- TODO remember to change this ID to match what page we're on.  id="page-selections", id="page-export"-->
    </div>
    <div id="tabula-dataview">

    </div>

    <div id="templates">
      <script type="text/template" id="page-template" >
        <span class="page-number"><%= number %>. </span>
        <div class="page" id="page-div-<%= number %>">
          <img onload="$(this).data('loaded', 'loaded');" src="<%= image_url %>" draggable="false" unselectable="on" > <!-- unselectable is for IE/Opera -->
        </div>
      </script>
      <script type="text/template" id="thumbnail-template" >
        <a href="#page-<%= number %>"><img src="<%= image_url %>"></a>
        <div class="remove">
          <span class="glyphicon glyphicon-remove delete-page"></span>
          <!-- <span title="rotate this page right" class="icon-repeat rotate-left"></span>
          <span title="rotate this page left" class="icon-repeat flip rotate-right"></span> -->
        </div>
        <p><%= number %></p>
      </script>

      <script type="text/template" id="export-control-panel-template">
        <form id="download-form" action="pdf/<%=pdf_id%>/data?format=csv" method="post">
          <div id="hidden-fields">
            <input type='hidden' class='data-query' name='new_filename' value='<%=original_filename%>' >
            <input type='hidden' class='data-query' name='coords' value='<%=list_of_coords%>' >
          </div>
          <!-- <input class="filename" name="new_filename" value="<%= new_filename || original_filename %>"></input> -->
          <span class="filename"><%= original_filename %></span>
          <label for="format">Export Format:</label>
          <select name="format" <%=disableIfNoData%> class="form-control format">
            <option value="csv">CSV</option>
            <option value="tsv">TSV</option>
            <option value="bbox">JSON (dimensions)</option>
            <option value="json">JSON (data)</option>
            <!-- <option value="&#x1F4A9;SV">&#x1F4A9;SV</option> -->
            <option value="zip">zip of CSVs</option>
            <!-- <option value="xml">XML</option> -->
            <option value="script">Script</option>
          </select>
          <button type="submit" <%=disableIfNoData%> id="download-data" class="btn btn-default" data-action='pdf/<%=pdf_id%>/data'>
            <span class="glyphicon glyphicon-refresh"></span>
            <span class="glyphicon glyphicon-download"></span>
            Export
          </button>
          <button type="button" id="copy-csv-to-clipboard" class="btn btn-default" <%=disableIfNoData%> <%=copyDisabled%> >
            <span class="glyphicon glyphicon-paperclip"></span>
            <span class="clipboard-text">Copy to Clipboard</span>
          </button>
        </form>
      </script>

      <script type="text/template" id="select-control-panel-template" >
        <span class="filename"><%= original_filename %></span>
        <div class="dropdown" <%= disable_load_template %> style="display: inline;">
          <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>
          <div id="template-dropdown-container" class="dropdown-menu">
            <ul>
              <li>
                <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>
              </li>
            </ul>
            <p style="margin-left:5px;">Load templates:</p>
            <div id="template-dropdown-templates-list-container">
            </div>
          </div>
        </div>


        <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>
        <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>



        <span style="float: right">
          <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>
        </span>




        <span style="clear: both;">
      </script>

      <script type="text/template" id="select-sidebar-template">
        <ul id="thumbnail-list" class="thumbnail-list">
        </ul>
      </script>

      <script type="text/template" id="export-page-sidebar-template">
          <h4>Is the extracted data incorrect?</h4>

          <p>You can revise your selected cells or try an alternate extraction method.</p>

          <h5>Revise Selected Cells</h5>
          <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>
          <p>
            <button type="button" class="btn btn-default" id="revise-selections"><span class="glyphicon glyphicon-arrow-left"></span> Revise selection(s)</button>
          </p>

          <h5>Choose Alternate Extraction Method</h5>

          <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>

          <div class="btn-group" data-toggle="buttons-radio" id="extraction-method-btns" <%=disableExtractionMethodButtons%> >
            <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>
            <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>
          </div>

          <p>
            Stream looks for <em>whitespace</em> between columns, while Lattice looks for <em>boundary lines</em> between columns.
          </p>

         <h5>Still look wrong?</h5>
          <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>
      </script>

      <!-- TODO: abstract out commonalities of select/export page templates -->
      <script type="text/template" id="export-page-template">
        <div id="sidebar">
        </div>

        <div id="main-pane">
            <div id="control-panel">
            </div>

           <h2>Preview of Extracted Tabular Data</h2>
            <div id="table-container">
            <% if(data.length){ %>
              <% _(data).each(function(table){ %>
              <table class="table table-bordered extracted-data">
                <tbody>
                <% _(table).each(function(row){ %>
                  <tr>
                    <% _(row).each(function(cell){ %>
                      <td><%= cell %></td>
                    <% }) %>
                  </tr>
                <% }) %>
                </tbody>
              </table>
              <% }) %>
            <% } else if (loading) { %>
             <div class="alert alert-success" id="loading"><span id="spinner"></span><span style="position: relative; left: 16px; font-size: 24px;">Loading...</span></div>
            <% } else if (error_message) { %>
               <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>
                 <pre class="error"><%= error_message %></pre>
            <% } else { %>
              <span class="no-data">No data.</span>
            <% } %>
            </div>
        </div>
      </script>

      <script type="text/template" id="pdf-view-template" >
        <div id="sidebar">
          <!-- thumbnails get rendered here by JS -->
        </div>
        <div id="main-pane">
          <div id="control-panel">
          </div>

          <div id="pages-container">
          </div>
        </div>
        <nestedscript type="text/javascript" src="js/vendor/spin.min.js"></nestedscript>
        <nestedscript type="text/javascript" src="js/resizableSelection.js"></nestedscript>
        <nestedscript type="text/javascript" src="js/rectangularSelector.js"></nestedscript>
        <nestedscript type="text/javascript" src="js/vendor/ZeroClipboard.min.js"></nestedscript>
        <!-- <nestedscript type="text/javascript" src="js/debug_pdf_view.js"></nestedscript>  -->
      </script>


      <script type="text/template" id="failed-uploads-template">
        <h4>Failed Uploads</h4>
        <ol id="failed-uploads">

        </ol>
      </script>
      <script type="text/template" id="failed-uploaded-file-template">
        <a href='/pdf/<%= id %>'><%= original_filename %></a>: <%= failure_message %>
      </script>


      <script type='text/template' id='file-upload-template'>
        <h5><%= filename %></h5>
        <span id="message"><%= message %></span>
        <ul class="list-unstyled">
          <% for(var warning in warnings) { %>
              <li class="text-danger">Warning: <%= warnings[warning] %></li>
          <% } %>
        </ul>
        <div class="progress">
          <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>
        </div>
      </script>

      <script type="text/template" id="progress-bars-template">
        <h4>Upload Progress</h4>
        <div id="progress-bars-container">

        </div>
      </script>

      <script type="text/template" id="new-version-template">
        <div class="alert alert-warning alert-dismissable" id="update-alert">
        <button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
        <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>)
        </div>
      </script>

      <script type="text/template" id="notification-template">
        <div class="alert alert-warning alert-dismissable" id="custom-alert">
        <button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
        <strong><%= notification.name %></strong> <span class="custom-alert-body"><%= notification.body %></span>
        </div>
      </script>


      <script type="text/template" id="uploader-template">
        <div class="container">
          <div class="jumbotron">

            <div id="new-version-alert"></div>
            <div id="notification-alert"></div>

            <div id="upload-form-container">
              <h4>Import one or more PDFs</h4>
              <form id="upload" action="upload.json" method="post" enctype="multipart/form-data" class="form-inline">

                <div class="input-group">
                  <!-- we are using this here: http://www.abeautifulsite.net/whipping-file-inputs-into-shape-with-bootstrap-3/ -->
                  <span class="input-group-btn">
                      <span class="btn btn-primary btn-file">
                          Browse&hellip; <input type="file" id="file" name="files[]" multiple accept="application/pdf">
                      </span>
                  </span>
                  <input type="text" class="form-control" readonly>
                </div>

                <!-- fix for the fact that IE11 is trash https://blog.yorkxin.org/posts/2014/02/06/ajax-with-formdata-is-broken-on-ie10-ie11/ -->
                <input type="hidden" name="_dontcare">

                <button type="submit" class="btn btn-default">Import</button>
              </form>

            </div>
            <div id="progress-container">
            </div>
              <hr>

              <div id="library-container">
                <h4>Imported PDFs</h4>

                <div id="file-list-container">
                <table class="table file-list tablesorter" id="fileTable">
                  <thead>
                    <tr>
                      <th>File Name</th>
                      <th style="min-width: 100px;">Size</th>
                      <th>Pages</th>
                      <th style="min-width: 150px;">Date Added</th>
                      <th>Remove</th>
                      <th>Process</th>
                    </tr>
                  </thead>
                  <tbody id="uploaded-files-container">
                  </tbody>
                </table>
                </div>
              </div>

          <hr />
          <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>

          </div> <!-- /jumbotron -->
        </div> <!-- /container -->

        <!-- we are using this here: http://www.abeautifulsite.net/whipping-file-inputs-into-shape-with-bootstrap-3/ -->
        <nestedscript type="text/javascript" src="js/vendor/upload-group.js"></nestedscript>
        <nestedscript type="text/javascript" src="js/vendor/jquery.tablesorter.min.js"></nestedscript>
        <nestedscript type="text/javascript" src="js/vendor/spin.min.js"></nestedscript>
      </script>

      <script type="text/template" id="uploaded-file-template">
        <td><a href='/pdf/<%= id %>'><%= original_filename %></a></td>
        <td><%= size ? Math.floor(size / 1024) : '??' %> kB</td>
        <td><%= page_count || '??' %></td>
        <td><%= new Date(parseInt(time) * 1000).toUTCString().slice(5, -7) %></td>
        <td><a href="javascript:"><span data-filename=<%= original_filename %> data-pdfid=<%= id %> class="glyphicon glyphicon-remove delete-pdf"></span></a></td>
        <td><a href="pdf/<%= id %>"><button type="button" class="btn btn-sm btn-success">Extract Data</button></a></td>
      </script>

      <script type="text/template" id="saved-template-library-item-template">
        <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>
        <td><%= selection_count %> selection<%= selection_count == "!" ? '' : 's' %></td>
        <td><%= page_count || '??' %></td>
        <td><%= new Date(parseInt(time) * 1000).toUTCString().slice(5, -7) %></td>
        <td><a href="javascript:"><span data-name=<%= name %> data-templateid=<%= id %> class="glyphicon glyphicon-remove delete-template"></span></a></td>
        <td>
          <form class="template-download-form" action="templates/<%= id %>.json" method="get" style="margin-bottom: 0;">
            <button type="submit" class="btn btn-default" data-action=>
              <span class="glyphicon glyphicon-download-alt download-template"></span>
              Download
            </button>
          </form>
        </td>
      </script>

      <script type="text/template" id="upload-error-template" >
        <div class="container-fluid">
          <div class="row-fluid">
            <div class="span6 offset3">
              <div class="hero-unit">
                <h1>Tabula</h1>
                <h2>Upload Error</h2>
                <p><span id="message"><%= message %></span></p>
              </div> <!-- /hero-unit -->
            </div>
          </div>
        </div>
      </script>

      <script type="text/template" id="about-template">
        <div class="container">
          <div class="jumbotron about">

            <h1>About Tabula</h1>
            <p>Tabula is a tool for liberating data tables trapped inside PDF files.</p>

            <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>
            <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>
            <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>
            <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>

            <h2>Who Uses Tabula?</h2>
            <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>
            <p>Grassroots organizations like SchoolCuts.org rely on Tabula to turn clunky documents into human-friendly public resources.</p>
            <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>

            <h2>Credits</h2>
            <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>
          </div> <!-- /jumbotron -->
        </div> <!-- /container -->
       </script>

      <script type="text/templates" id="templates-template">
        <div class="container">
          <div class="jumbotron help">
            <h1>My Saved Templates</h1>
            <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>
            <p>To use a template, <a href="">upload a file</a> or select it from <a href="">My Files</a>.</p>
            <div id="template-library-container">
              <div id="file-list-container">
              <table class="table file-list" id="templateTable">
                <thead>
                  <tr>
                    <th>Template Name</th>
                    <th>Selection Count</th>
                    <th>Page Count</th>
                    <th>Date Added</th>
                    <th>Remove</th>
                    <th>Download</th>
                  </tr>
                </thead>
                <tbody id="saved-templates-container">
                </tbody>
              </table>
              </div>
            </div>

            <div id="template-upload-form-container">
              <h2>Import one or more Tabula Templates</h2>
              <p style="font-size: small;">Once you save a Tabula Template, it'll appear here.</p>
              <form id="uploadtemplate" action="templates/upload.json" method="post" enctype="multipart/form-data" class="form-inline">

                <div class="input-group">
                  <!-- we are using this here: http://www.abeautifulsite.net/whipping-file-inputs-into-shape-with-bootstrap-3/ -->
                  <span class="input-group-btn">
                      <span class="btn btn-primary btn-file">
                          Browse&hellip; <input type="file" id="file" name="files[]" multiple accept="application/json">
                      </span>
                  </span>
                  <input type="text" class="form-control" readonly>
                </div>

                <!-- fix for the fact that IE11 is trash https://blog.yorkxin.org/posts/2014/02/06/ajax-with-formdata-is-broken-on-ie10-ie11/ -->
                <input type="hidden" name="_dontcare">

                <button type="submit" class="btn btn-default">Import</button>
              </form>

            </div>
          </div> <!-- /jumbotron -->
        </div> <!-- /container -->
        <nestedscript type="text/javascript" src="js/vendor/upload-group.js"></nestedscript>
        <nestedscript type="text/javascript" src="js/vendor/jquery.tablesorter.min.js"></nestedscript>
      </script>


      <script type="text/template" id="help-template">
        <div class="container">
          <div class="jumbotron help">
          <h3 name="howto">How to Use Tabula</h3>
          <ol>
            <li>Upload a PDF file containing a data table.</li>
            <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>
            <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>
            <li>Click the Download button.</li>
            <li>Now you can work with your data as text file or a spreadsheet rather than a PDF! <br>
            (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>
          </ol>
          <p>Note: Tabula only works on text-based PDFs, not scanned documents.</p>
          <h3 name="trouble">Having trouble with Tabula?</h3>
          <ol>
          <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>
          <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>
          <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>
          <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>
          <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>
          <!-- 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 -->
          </ol>

          </div> <!-- /jumbotron -->
        </div> <!-- /container -->
       </script>
       <script type="text/template" id="notifications-approval-template">
          <div id="notifications-approval-clicky">
            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.
            <input type="button" id="notifications-approval-okay" value="Okay! Notify me and count me." />
            <input type="button" id="notifications-approval-opt-out" value="No thanks" />
            <a id="notifications-approval-close" >✕</a>
          </div>
       </script>

    </div> <!-- /templates -->




    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->

    </script> <!-- TODO: move this to tabula.js, only run it if we're in upload page viewer -->

    <script type="text/javascript" src="js/tabula.js?_cachebuster=201510300905"></script> <!-- actually starts Tabula -->
    <script type="text/javascript" src="js/template_library.js?_cachebuster=201510300905"></script> <!-- needed on almost all pages -->

  </body>
</html>


================================================
FILE: webapp/static/css/_bootstrap-variables.scss
================================================
// Override Bootstrap variables here (defaults from bootstrap-sass v3.3.1.0):

// When true, asset path helpers are used, otherwise the regular CSS `url()` is used.
// When there no function is defined, `fn('')` is parsed as string that equals the right hand side
// NB: in Sass 3.3 there is a native function: function-exists(twbs-font-path)
// $bootstrap-sass-asset-helper: (twbs-font-path("") != unquote('twbs-font-path("")'))

//
// Variables
// --------------------------------------------------

//== Colors
//
//## Gray and brand colors for use across Bootstrap.

// $gray-base:              #000
// $gray-darker:            lighten($gray-base, 13.5%) // #222
// $gray-dark:              lighten($gray-base, 20%)   // #333
// $gray:                   lighten($gray-base, 33.5%) // #555
// $gray-light:             lighten($gray-base, 46.7%) // #777
// $gray-lighter:           lighten($gray-base, 93.5%) // #eee

// $brand-primary:         darken(#428bca, 6.5%)
// $brand-success:         #5cb85c
// $brand-info:            #5bc0de
// $brand-warning:         #f0ad4e
// $brand-danger:          #d9534f

//== Scaffolding
//
//## Settings for some of the most global styles.

//** Background color for `<body>`.
// $body-bg:               #fff
//** Global text color on `<body>`.
// $text-color:            $gray-dark

//** Global textual link color.
// $link-color:            $brand-primary
//** Link hover color set via `darken()` function.
// $link-hover-color:      darken($link-color, 15%)
//** Link hover decoration.
// $link-hover-decoration: underline

//== Typography
//
//## Font, line-height, and color for body text, headings, and more.

// $font-family-sans-serif:  "Helvetica Neue", Helvetica, Arial, sans-serif
// $font-family-serif:       Georgia, "Times New Roman", Times, serif
//** Default monospace fonts for `<code>`, `<kbd>`, and `<pre>`.
// $font-family-monospace:   Menlo, Monaco, Consolas, "Courier New", monospace
// $font-family-base:        $font-family-sans-serif

// $font-size-base:          14px
// $font-size-large:         ceil(($font-size-base * 1.25)) // ~18px
// $font-size-small:         ceil(($font-size-base * 0.85)) // ~12px

// $font-size-h1:            floor(($font-size-base * 2.6)) // ~36px
// $font-size-h2:            floor(($font-size-base * 2.15)) // ~30px
// $font-size-h3:            ceil(($font-size-base * 1.7)) // ~24px
// $font-size-h4:            ceil(($font-size-base * 1.25)) // ~18px
// $font-size-h5:            $font-size-base
// $font-size-h6:            ceil(($font-size-base * 0.85)) // ~12px

//** Unit-less `line-height` for use in components like buttons.
// $line-height-base:        1.428571429 // 20/14
//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
// $line-height-computed:    floor(($font-size-base * $line-height-base)) // ~20px

//** By default, this inherits from the `<body>`.
// $headings-font-family:    inherit
// $headings-font-weight:    500
// $headings-line-height:    1.1
// $headings-color:          inherit

//== Iconography
//
//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.

//** Load fonts from this directory.

// [converter] Asset helpers such as Sprockets and Node.js Mincer do not resolve relative paths
// $icon-font-path: if($bootstrap-sass-asset-helper, "bootstrap/", "../fonts/bootstrap/")

//** File name for all font files.
// $icon-font-name:          "glyphicons-halflings-regular"
//** Element ID within SVG icon file.
// $icon-font-svg-id:        "glyphicons_halflingsregular"

//== Components
//
//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).

// $padding-base-vertical:     6px
// $padding-base-horizontal:   12px

// $padding-large-vertical:    10px
// $padding-large-horizontal:  16px

// $padding-small-vertical:    5px
// $padding-small-horizontal:  10px

// $padding-xs-vertical:       1px
// $padding-xs-horizontal:     5px

// $line-height-large:         1.33
// $line-height-small:         1.5

// $border-radius-base:        4px
// $border-radius-large:       6px
// $border-radius-small:       3px

//** Global color for active items (e.g., navs or dropdowns).
// $component-active-color:    #fff
//** Global background color for active items (e.g., navs or dropdowns).
// $component-active-bg:       $brand-primary

//** Width of the `border` for generating carets that indicator dropdowns.
// $caret-width-base:          4px
//** Carets increase slightly in size for larger components.
// $caret-width-large:         5px

//== Tables
//
//## Customizes the `.table` component with basic values, each used across all table variations.

//** Padding for `<th>`s and `<td>`s.
// $table-cell-padding:            8px
//** Padding for cells in `.table-condensed`.
// $table-condensed-cell-padding:  5px

//** Default background color used for all tables.
// $table-bg:                      transparent
//** Background color used for `.table-striped`.
// $table-bg-accent:               #f9f9f9
//** Background color used for `.table-hover`.
// $table-bg-hover:                #f5f5f5
// $table-bg-active:               $table-bg-hover

//** Border color for table and cell borders.
// $table-border-color:            #ddd

//== Buttons
//
//## For each of Bootstrap's buttons, define text, background and border color.

// $btn-font-weight:                normal

// $btn-default-color:              #333
// $btn-default-bg:                 #fff
// $btn-default-border:             #ccc

// $btn-primary-color:              #fff
// $btn-primary-bg:                 $brand-primary
// $btn-primary-border:             darken($btn-primary-bg, 5%)

// $btn-success-color:              #fff
// $btn-success-bg:                 $brand-success
// $btn-success-border:             darken($btn-success-bg, 5%)

// $btn-info-color:                 #fff
// $btn-info-bg:                    $brand-info
// $btn-info-border:                darken($btn-info-bg, 5%)

// $btn-warning-color:              #fff
// $btn-warning-bg:                 $brand-warning
// $btn-warning-border:             darken($btn-warning-bg, 5%)

// $btn-danger-color:               #fff
// $btn-danger-bg:                  $brand-danger
// $btn-danger-border:              darken($btn-danger-bg, 5%)

// $btn-link-disabled-color:        $gray-light

//== Forms
//
//##

//** `<input>` background color
// $input-bg:                       #fff
//** `<input disabled>` background color
// $input-bg-disabled:              $gray-lighter

//** Text color for `<input>`s
// $input-color:                    $gray
//** `<input>` border color
// $input-border:                   #ccc

// TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4
//** Default `.form-control` border radius
// $input-border-radius:            $border-radius-base
//** Large `.form-control` border radius
// $input-border-radius-large:      $border-radius-large
//** Small `.form-control` border radius
// $input-border-radius-small:      $border-radius-small

//** Border color for inputs on focus
// $input-border-focus:             #66afe9

//** Placeholder text color
// $input-color-placeholder:        #999

//** Default `.form-control` height
// $input-height-base:              ($line-height-computed + ($padding-base-vertical * 2) + 2)
//** Large `.form-control` height
// $input-height-large:             (ceil($font-size-large * $line-height-large) + ($padding-large-vertical * 2) + 2)
//** Small `.form-control` height
// $input-height-small:             (floor($font-size-small * $line-height-small) + ($padding-small-vertical * 2) + 2)

// $legend-color:                   $gray-dark
// $legend-border-color:            #e5e5e5

//** Background color for textual input addons
// $input-group-addon-bg:           $gray-lighter
//** Border color for textual input addons
// $input-group-addon-border-color: $input-border

//** Disabled cursor for form controls and buttons.
// $cursor-disabled:                not-allowed

//== Dropdowns
//
//## Dropdown menu container and contents.

//** Background for the dropdown menu.
// $dropdown-bg:                    #fff
//** Dropdown menu `border-color`.
// $dropdown-border:                rgba(0,0,0,.15)
//** Dropdown menu `border-color` **for IE8**.
// $dropdown-fallback-border:       #ccc
//** Divider color for between dropdown items.
// $dropdown-divider-bg:            #e5e5e5

//** Dropdown link text color.
// $dropdown-link-color:            $gray-dark
//** Hover color for dropdown links.
// $dropdown-link-hover-color:      darken($gray-dark, 5%)
//** Hover background for dropdown links.
// $dropdown-link-hover-bg:         #f5f5f5

//** Active dropdown menu item text color.
// $dropdown-link-active-color:     $component-active-color
//** Active dropdown menu item background color.
// $dropdown-link-active-bg:        $component-active-bg

//** Disabled dropdown menu item background color.
// $dropdown-link-disabled-color:   $gray-light

//** Text color for headers within dropdown menus.
// $dropdown-header-color:          $gray-light

//** Deprecated `$dropdown-caret-color` as of v3.1.0
// $dropdown-caret-color:           #000

//-- Z-index master list
//
// Warning: Avoid customizing these values. They're used for a bird's eye view
// of components dependent on the z-axis and are designed to all work together.
//
// Note: These variables are not generated into the Customizer.

// $zindex-navbar:            1000
// $zindex-dropdown:          1000
// $zindex-popover:           1060
// $zindex-tooltip:           1070
// $zindex-navbar-fixed:      1030
// $zindex-modal:             1040

//== Media queries breakpoints
//
//## Define the breakpoints at which your layout will change, adapting to different screen sizes.

// Extra small screen / phone
//** Deprecated `$screen-xs` as of v3.0.1
// $screen-xs:                  480px
//** Deprecated `$screen-xs-min` as of v3.2.0
// $screen-xs-min:              $screen-xs
//** Deprecated `$screen-phone` as of v3.0.1
// $screen-phone:               $screen-xs-min

// Small screen / tablet
//** Deprecated `$screen-sm` as of v3.0.1
// $screen-sm:                  768px
// $screen-sm-min:              $screen-sm
//** Deprecated `$screen-tablet` as of v3.0.1
// $screen-tablet:              $screen-sm-min

// Medium screen / desktop
//** Deprecated `$screen-md` as of v3.0.1
// $screen-md:                  992px
// $screen-md-min:              $screen-md
//** Deprecated `$screen-desktop` as of v3.0.1
// $screen-desktop:             $screen-md-min

// Large screen / wide desktop
//** Deprecated `$screen-lg` as of v3.0.1
// $screen-lg:                  1200px
// $screen-lg-min:              $screen-lg
//** Deprecated `$screen-lg-desktop` as of v3.0.1
// $screen-lg-desktop:          $screen-lg-min

// So media queries don't overlap when required, provide a maximum
// $screen-xs-max:              ($screen-sm-min - 1)
// $screen-sm-max:              ($screen-md-min - 1)
// $screen-md-max:              ($screen-lg-min - 1)

//== Grid system
//
//## Define your custom responsive grid.

//** Number of columns in the grid.
// $grid-columns:              12
//** Padding between columns. Gets divided in half for the left and right.
// $grid-gutter-width:         30px
// Navbar collapse
//** Point at which the navbar becomes uncollapsed.
// $grid-float-breakpoint:     $screen-sm-min
//** Point at which the navbar begins collapsing.
// $grid-float-breakpoint-max: ($grid-float-breakpoint - 1)

//== Container sizes
//
//## Define the maximum width of `.container` for different screen sizes.

// Small screen / tablet
// $container-tablet:             (720px + $grid-gutter-width)
//** For `$screen-sm-min` and up.
// $container-sm:                 $container-tablet

// Medium screen / desktop
// $container-desktop:            (940px + $grid-gutter-width)
//** For `$screen-md-min` and up.
// $container-md:                 $container-desktop

// Large screen / wide desktop
// $container-large-desktop:      (1140px + $grid-gutter-width)
//** For `$screen-lg-min` and up.
// $container-lg:                 $container-large-desktop

//== Navbar
//
//##

// Basics of a navbar
// $navbar-height:                    50px
// $navbar-margin-bottom:             $line-height-computed
// $navbar-border-radius:             $border-radius-base
// $navbar-padding-horizontal:        floor(($grid-gutter-width / 2))
// $navbar-padding-vertical:          (($navbar-height - $line-height-computed) / 2)
// $navbar-collapse-max-height:       340px

// $navbar-default-color:             #777
// $navbar-default-bg:                #f8f8f8
// $navbar-default-border:            darken($navbar-default-bg, 6.5%)

// Navbar links
// $navbar-default-link-color:                #777
// $navbar-default-link-hover-color:          #333
// $navbar-default-link-hover-bg:             transparent
// $navbar-default-link-active-color:         #555
// $navbar-default-link-active-bg:            darken($navbar-default-bg, 6.5%)
// $navbar-default-link-disabled-color:       #ccc
// $navbar-default-link-disabled-bg:          transparent

// Navbar brand label
// $navbar-default-brand-color:               $navbar-default-link-color
// $navbar-default-brand-hover-color:         darken($navbar-default-brand-color, 10%)
// $navbar-default-brand-hover-bg:            transparent

// Navbar toggle
// $navbar-default-toggle-hover-bg:           #ddd
// $navbar-default-toggle-icon-bar-bg:        #888
// $navbar-default-toggle-border-color:       #ddd

// Inverted navbar
// Reset inverted navbar basics
// $navbar-inverse-color:                      lighten($gray-light, 15%)
// $navbar-inverse-bg:                         #222
// $navbar-inverse-border:                     darken($navbar-inverse-bg, 10%)

// Inverted navbar links
// $navbar-inverse-link-color:                 lighten($gray-light, 15%)
// $navbar-inverse-link-hover-color:           #fff
// $navbar-inverse-link-hover-bg:              transparent
// $navbar-inverse-link-active-color:          $navbar-inverse-link-hover-color
// $navbar-inverse-link-active-bg:             darken($navbar-inverse-bg, 10%)
// $navbar-inverse-link-disabled-color:        #444
// $navbar-inverse-link-disabled-bg:           transparent

// Inverted navbar brand label
// $navbar-inverse-brand-color:                $navbar-inverse-link-color
// $navbar-inverse-brand-hover-color:          #fff
// $navbar-inverse-brand-hover-bg:             transparent

// Inverted navbar toggle
// $navbar-inverse-toggle-hover-bg:            #333
// $navbar-inverse-toggle-icon-bar-bg:         #fff
// $navbar-inverse-toggle-border-color:        #333

//== Navs
//
//##

//=== Shared nav styles
// $nav-link-padding:                          10px 15px
// $nav-link-hover-bg:                         $gray-lighter

// $nav-disabled-link-color:                   $gray-light
// $nav-disabled-link-hover-color:             $gray-light

//== Tabs
// $nav-tabs-border-color:                     #ddd

// $nav-tabs-link-hover-border-color:          $gray-lighter

// $nav-tabs-active-link-hover-bg:             $body-bg
// $nav-tabs-active-link-hover-color:          $gray
// $nav-tabs-active-link-hover-border-color:   #ddd

// $nav-tabs-justified-link-border-color:            #ddd
// $nav-tabs-justified-active-link-border-color:     $body-bg

//== Pills
// $nav-pills-border-radius:                   $border-radius-base
// $nav-pills-active-link-hover-bg:            $component-active-bg
// $nav-pills-active-link-hover-color:         $component-active-color

//== Pagination
//
//##

// $pagination-color:                     $link-color
// $pagination-bg:                        #fff
// $pagination-border:                    #ddd

// $pagination-hover-color:               $link-hover-color
// $pagination-hover-bg:                  $gray-lighter
// $pagination-hover-border:              #ddd

// $pagination-active-color:              #fff
// $pagination-active-bg:                 $brand-primary
// $pagination-active-border:             $brand-primary

// $pagination-disabled-color:            $gray-light
// $pagination-disabled-bg:               #fff
// $pagination-disabled-border:           #ddd

//== Pager
//
//##

// $pager-bg:                             $pagination-bg
// $pager-border:                         $pagination-border
// $pager-border-radius:                  15px

// $pager-hover-bg:                       $pagination-hover-bg

// $pager-active-bg:                      $pagination-active-bg
// $pager-active-color:                   $pagination-active-color

// $pager-disabled-color:                 $pagination-disabled-color

//== Jumbotron
//
//##

// $jumbotron-padding:              30px
// $jumbotron-color:                inherit
// $jumbotron-bg:                   $gray-lighter
// $jumbotron-heading-color:        inherit
// $jumbotron-font-size:            ceil(($font-size-base * 1.5))

//== Form states and alerts
//
//## Define colors for form feedback states and, by default, alerts.

// $state-success-text:             #3c763d
// $state-success-bg:               #dff0d8
// $state-success-border:           darken(adjust-hue($state-success-bg, -10), 5%)

// $state-info-text:                #31708f
// $state-info-bg:                  #d9edf7
// $state-info-border:              darken(adjust-hue($state-info-bg, -10), 7%)

// $state-warning-text:             #8a6d3b
// $state-warning-bg:               #fcf8e3
// $state-warning-border:           darken(adjust-hue($state-warning-bg, -10), 5%)

// $state-danger-text:              #a94442
// $state-danger-bg:                #f2dede
// $state-danger-border:            darken(adjust-hue($state-danger-bg, -10), 5%)

//== Tooltips
//
//##

//** Tooltip max width
// $tooltip-max-width:           200px
//** Tooltip text color
// $tooltip-color:               #fff
//** Tooltip background color
// $tooltip-bg:                  #000
// $tooltip-opacity:             .9

//** Tooltip arrow width
// $tooltip-arrow-width:         5px
//** Tooltip arrow color
// $tooltip-arrow-color:         $tooltip-bg

//== Popovers
//
//##

//** Popover body background color
// $popover-bg:                          #fff
//** Popover maximum width
// $popover-max-width:                   276px
//** Popover border color
// $popover-border-color:                rgba(0,0,0,.2)
//** Popover fallback border color
// $popover-fallback-border-color:       #ccc

//** Popover title background color
// $popover-title-bg:                    darken($popover-bg, 3%)

//** Popover arrow width
// $popover-arrow-width:                 10px
//** Popover arrow color
// $popover-arrow-color:                 $popover-bg

//** Popover outer arrow width
// $popover-arrow-outer-width:           ($popover-arrow-width + 1)
//** Popover outer arrow color
// $popover-arrow-outer-color:           fade_in($popover-border-color, 0.05)
//** Popover outer arrow fallback color
// $popover-arrow-outer-fallback-color:  darken($popover-fallback-border-color, 20%)

//== Labels
//
//##

//** Default label background color
// $label-default-bg:            $gray-light
//** Primary label background color
// $label-primary-bg:            $brand-primary
//** Success label background color
// $label-success-bg:            $brand-success
//** Info label background color
// $label-info-bg:               $brand-info
//** Warning label background color
// $label-warning-bg:            $brand-warning
//** Danger label background color
// $label-danger-bg:             $brand-danger

//** Default label text color
// $label-color:                 #fff
//** Default text color of a linked label
// $label-link-hover-color:      #fff

//== Modals
//
//##

//** Padding applied to the modal body
// $modal-inner-padding:         15px

//** Padding applied to the modal title
// $modal-title-padding:         15px
//** Modal title line-height
// $modal-title-line-height:     $line-height-base

//** Background color of modal content area
// $modal-content-bg:                             #fff
//** Modal content border color
// $modal-content-border-color:                   rgba(0,0,0,.2)
//** Modal content border color **for IE8**
// $modal-content-fallback-border-color:          #999

//** Modal backdrop background color
// $modal-backdrop-bg:           #000
//** Modal backdrop opacity
// $modal-backdrop-opacity:      .5
//** Modal header border color
// $modal-header-border-color:   #e5e5e5
//** Modal footer border color
// $modal-footer-border-color:   $modal-header-border-color

// $modal-lg:                    900px
// $modal-md:                    600px
// $modal-sm:                    300px

//== Alerts
//
//## Define alert colors, border radius, and padding.

// $alert-padding:               15px
// $alert-border-radius:         $border-radius-base
// $alert-link-font-weight:      bold

// $alert-success-bg:            $state-success-bg
// $alert-success-text:          $state-success-text
// $alert-success-border:        $state-success-border

// $alert-info-bg:               $state-info-bg
// $alert-info-text:             $state-info-text
// $alert-info-border:           $state-info-border

// $alert-warning-bg:            $state-warning-bg
// $alert-warning-text:          $state-warning-text
// $alert-warning-border:        $state-warning-border

// $alert-danger-bg:             $state-danger-bg
// $alert-danger-text:           $state-danger-text
// $alert-danger-border:         $state-danger-border

//== Progress bars
//
//##

//** Background color of the whole progress component
// $progress-bg:                 #f5f5f5
//** Progress bar text color
// $progress-bar-color:          #fff
//** Variable for setting rounded corners on progress bar.
// $progress-border-radius:      $border-radius-base

//** Default progress bar color
// $progress-bar-bg:             $brand-primary
//** Success progress bar color
// $progress-bar-success-bg:     $brand-success
//** Warning progress bar color
// $progress-bar-warning-bg:     $brand-warning
//** Danger progress bar color
// $progress-bar-danger-bg:      $brand-danger
//** Info progress bar color
// $progress-bar-info-bg:        $brand-info

//== List group
//
//##

//** Background color on `.list-group-item`
// $list-group-bg:                 #fff
//** `.list-group-item` border color
// $list-group-border:             #ddd
//** List group border radius
// $list-group-border-radius:      $border-radius-base

//** Background color of single list items on hover
// $list-group-hover-bg:           #f5f5f5
//** Text color of active list items
// $list-group-active-color:       $component-active-color
//** Background color of active list items
// $list-group-active-bg:          $component-active-bg
//** Border color of active list elements
// $list-group-active-border:      $list-group-active-bg
//** Text color for content within active list items
// $list-group-active-text-color:  lighten($list-group-active-bg, 40%)

//** Text color of disabled list items
// $list-group-disabled-color:      $gray-light
//** Background color of disabled list items
// $list-group-disabled-bg:         $gray-lighter
//** Text color for content within disabled list items
// $list-group-disabled-text-color: $list-group-disabled-color

// $list-group-link-color:         #555
// $list-group-link-hover-color:   $list-group-link-color
// $list-group-link-heading-color: #333

//== Panels
//
//##

// $panel-bg:                    #fff
// $panel-body-padding:          15px
// $panel-heading-padding:       10px 15px
// $panel-footer-padding:        $panel-heading-padding
// $panel-border-radius:         $border-radius-base

//** Border color for elements within panels
// $panel-inner-border:          #ddd
// $panel-footer-bg:             #f5f5f5

// $panel-default-text:          $gray-dark
// $panel-default-border:        #ddd
// $panel-default-heading-bg:    #f5f5f5

// $panel-primary-text:          #fff
// $panel-primary-border:        $brand-primary
// $panel-primary-heading-bg:    $brand-primary

// $panel-success-text:          $state-success-text
// $panel-success-border:        $state-success-border
// $panel-success-heading-bg:    $state-success-bg

// $panel-info-text:             $state-info-text
// $panel-info-border:           $state-info-border
// $panel-info-heading-bg:       $state-info-bg

// $panel-warning-text:          $state-warning-text
// $panel-warning-border:        $state-warning-border
// $panel-warning-heading-bg:    $state-warning-bg

// $panel-danger-text:           $state-danger-text
// $panel-danger-border:         $state-danger-border
// $panel-danger-heading-bg:     $state-danger-bg

//== Thumbnails
//
//##

//** Padding around the thumbnail image
// $thumbnail-padding:           4px
//** Thumbnail background color
// $thumbnail-bg:                $body-bg
//** Thumbnail border color
// $thumbnail-border:            #ddd
//** Thumbnail border radius
// $thumbnail-border-radius:     $border-radius-base

//** Custom text color for thumbnail captions
// $thumbnail-caption-color:     $text-color
//** Padding around the thumbnail caption
// $thumbnail-caption-padding:   9px

//== Wells
//
//##

// $well-bg:                     #f5f5f5
// $well-border:                 darken($well-bg, 7%)

//== Badges
//
//##

// $badge-color:                 #fff
//** Linked badge text color on hover
// $badge-link-hover-color:      #fff
// $badge-bg:                    $gray-light

//** Badge text color in active nav link
// $badge-active-color:          $link-color
//** Badge background color in active nav link
// $badge-active-bg:             #fff

// $badge-font-weight:           bold
// $badge-line-height:           1
// $badge-border-radius:         10px

//== Breadcrumbs
//
//##

// $breadcrumb-padding-vertical:   8px
// $breadcrumb-padding-horizontal: 15px
//** Breadcrumb background color
// $breadcrumb-bg:                 #f5f5f5
//** Breadcrumb text color
// $breadcrumb-color:              #ccc
//** Text color of current page in the breadcrumb
// $breadcrumb-active-color:       $gray-light
//** Textual separator for between breadcrumb elements
// $breadcrumb-separator:          "/"

//== Carousel
//
//##

// $carousel-text-shadow:                        0 1px 2px rgba(0,0,0,.6)

// $carousel-control-color:                      #fff
// $carousel-control-width:                      15%
// $carousel-control-opacity:                    .5
// $carousel-control-font-size:                  20px

// $carousel-indicator-active-bg:                #fff
// $carousel-indicator-border-color:             #fff

// $carousel-caption-color:                      #fff

//== Close
//
//##

// $close-font-weight:           bold
// $close-color:                 #000
// $close-text-shadow:           0 1px 0 #fff

//== Code
//
//##

// $code-color:                  #c7254e
// $code-bg:                     #f9f2f4

// $kbd-color:                   #fff
// $kbd-bg:                      #333

// $pre-bg:                      #f5f5f5
// $pre-color:                   $gray-dark
// $pre-border-color:            #ccc
// $pre-scrollable-max-height:   340px

//== Type
//
//##

//** Horizontal offset for forms and lists.
// $component-offset-horizontal: 180px
//** Text muted color
// $text-muted:                  $gray-light
//** Abbreviations and acronyms border color
// $abbr-border-color:           $gray-light
//** Headings small color
// $headings-small-color:        $gray-light
//** Blockquote small color
// $blockquote-small-color:      $gray-light
//** Blockquote font size
// $blockquote-font-size:        ($font-size-base * 1.25)
//** Blockquote border color
// $blockquote-border-color:     $gray-lighter
//** Page header border color
// $page-header-border-color:    $gray-lighter
//** Width of horizontal description list titles
// $dl-horizontal-offset:        $component-offset-horizontal
//** Horizontal line color.
// $hr-border:                   $gray-lighter


================================================
FILE: webapp/static/css/selectors.css
================================================
.thumbnail-list li div.selection-show {
  position: absolute;
  border: 1px dashed red;
  display: none;
  pointer-events: none;
}

/* selections */
.repeat-lassos-group {
  position: absolute;
  right: -185px;
  bottom: -35px;
}

/* rectangularSelector.js classes */
.selection-box, .table-region {
  position: absolute;
  border: 1px dashed rgba(255, 87, 0, 0.8);
  background: rgba(255, 87, 0, 0.2);
  box-sizing: border-box;
}
.selection-box:hover, .table-region:hover {
  cursor: pointer;
}

.selection-box {
  z-index: 42;
  width: 0;
  height: 0;
  visibility: hidden;
}

.table-region {
  top: 0;
  left: 0;
  z-index: 21;
}

div.table-region .resize-handle {
  position: absolute;
}

div.table-region .n-border {
  width: calc(100% - 10px);
  top: -5px;
  left: 5px;
  height: 10px;
}

div.table-region .s-border {
  width: calc(100% - 10px);
  bottom: -5px;
  left: 5px;
  height: 10px;
}

div.table-region .w-border {
  height: calc(100% - 10px);
  left: -5px;
  top: 5px;
  width: 10px;
}

div.table-region .e-border {
  height: calc(100% - 10px);
  top: 5px;
  right: -5px;
  width: 10px;
}

div.table-region .nw-border {
  width: 10px;
  height: 10px;
  top: -5px;
  left: -5px;
}

div.table-region .ne-border {
  width: 10px;
  height: 10px;
  top: -5px;
  right: -5px;
}

div.table-region .sw-border {
  width: 10px;
  height: 10px;
  bottom: -5px;
  left: -5px;
}

div.table-region .se-border {
  width: 10px;
  height: 10px;
  bottom: -5px;
  right: -5px;
}

div.table-region .n-border:hover {
  cursor: n-resize;
}

div.table-region .nw-border:hover {
  cursor: nw-resize;
}

div.table-region .ne-border:hover {
  cursor: ne-resize;
}

div.table-region .s-border:hover {
  cursor: s-resize;
}

div.table-region .sw-border:hover {
  cursor: sw-resize;
}

div.table-region .se-border:hover {
  cursor: se-resize;
}

div.table-region .w-border:hover {
  cursor: w-resize;
}

div.table-region .e-border:hover {
  cursor: e-resize;
}

div.table-region button[name=close] {
  font-weight: bold;
  border: 0;
  background-color: transparent;
  padding: 0;
  font-size: 20px;
  position: relative;
  top: -25px;
  left: 100%;
  margin-left: 5px;
}

div.table-region button[name=close]:hover {
  color: red;
}


================================================
FILE: webapp/static/css/styles.css
================================================
@charset "UTF-8";
/*!
 * WARNING: Don't edit this file by hand! Instead, you should be using Compass.
 * Edit the file in webapp/static/sass/styles.scss (or webapp/static/sass/selectors.scss)
 * Then, run `$ compass watch` to automatically re-compile the scss file into "normal" CSS on save.
 * Alternatively, run `$ compass compile` to re-compile the SCSS once.
 */
/*! normalize.css v3.0.1 | MIT License | git.io/normalize */
html {
  font-family: sans-serif;
  -ms-text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
}

article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
nav,
section,
summary {
  display: block;
}

audio,
canvas,
progress,
video {
  display: inline-block;
  vertical-align: baseline;
}

audio:not([controls]) {
  display: none;
  height: 0;
}

[hidden],
template {
  display: none;
}

a {
  background: transparent;
}

a:active,
a:hover {
  outline: 0;
}

abbr[title] {
  border-bottom: 1px dotted;
}

b,
strong {
  font-weight: bold;
}

dfn {
  font-style: italic;
}

h1 {
  font-size: 2em;
  margin: 0.67em 0;
}

mark {
  background: #ff0;
  color: #000;
}

small {
  font-size: 80%;
}

sub,
sup {
  font-size: 75%;
  line-height: 0;
  position: relative;
  vertical-align: baseline;
}

sup {
  top: -0.5em;
}

sub {
  bottom: -0.25em;
}

img {
  border: 0;
}

svg:not(:root) {
  overflow: hidden;
}

figure {
  margin: 1em 40px;
}

hr {
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  height: 0;
}

pre {
  overflow: auto;
}

code,
kbd,
pre,
samp {
  font-family: monospace, monospace;
  font-size: 1em;
}

button,
input,
optgroup,
select,
textarea {
  color: inherit;
  font: inherit;
  margin: 0;
}

button {
  overflow: visible;
}

button,
select {
  text-transform: none;
}

button,
html input[type="button"],
input[type="reset"],
input[type="submit"] {
  -webkit-appearance: button;
  cursor: pointer;
}

button[disabled],
html input[disabled] {
  cursor: default;
}

button::-moz-focus-inner,
input::-moz-focus-inner {
  border: 0;
  padding: 0;
}

input {
  line-height: normal;
}

input[type="checkbox"],
input[type="radio"] {
  box-sizing: border-box;
  padding: 0;
}

input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
  height: auto;
}

input[type="search"] {
  -webkit-appearance: textfield;
  -moz-box-sizing: content-box;
  -webkit-box-sizing: content-box;
  box-sizing: content-box;
}

input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
  -webkit-appearance: none;
}

fieldset {
  border: 1px solid #c0c0c0;
  margin: 0 2px;
  padding: 0.35em 0.625em 0.75em;
}

legend {
  border: 0;
  padding: 0;
}

textarea {
  overflow: auto;
}

optgroup {
  font-weight: bold;
}

table {
  border-collapse: collapse;
  border-spacing: 0;
}

td,
th {
  padding: 0;
}

@media print {
  * {
    text-shadow: none !important;
    color: #000 !important;
    background: transparent !important;
    box-shadow: none !important;
  }

  a,
  a:visited {
    text-decoration: underline;
  }

  a[href]:after {
    content: " (" attr(href) ")";
  }

  abbr[title]:after {
    content: " (" attr(title) ")";
  }

  a[href^="javascript:"]:after,
  a[href^="#"]:after {
    content: "";
  }

  pre,
  blockquote {
    border: 1px solid #999;
    page-break-inside: avoid;
  }

  thead {
    display: table-header-group;
  }

  tr,
  img {
    page-break-inside: avoid;
  }

  img {
    max-width: 100% !important;
  }

  p,
  h2,
  h3 {
    orphans: 3;
    widows: 3;
  }

  h2,
  h3 {
    page-break-after: avoid;
  }

  select {
    background: #fff !important;
  }

  .navbar {
    display: none;
  }

  .table td,
  .table th {
    background-color: #fff !important;
  }

  .btn > .caret,
  .dropup > .btn > .caret {
    border-top-color: #000 !important;
  }

  .label {
    border: 1px solid #000;
  }

  .table {
    border-collapse: collapse !important;
  }

  .table-bordered th,
  .table-bordered td {
    border: 1px solid #ddd !important;
  }
}
@font-face {
  font-family: 'Glyphicons Halflings';
  src: url(webapp/fonts/bootstrap/glyphicons-halflings-regular.eot);
  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");
}
.glyphicon {
  position: relative;
  top: 1px;
  display: inline-block;
  font-family: 'Glyphicons Halflings';
  font-style: normal;
  font-weight: normal;
  line-height: 1;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.glyphicon-asterisk:before {
  content: "\2a";
}

.glyphicon-plus:before {
  content: "\2b";
}

.glyphicon-euro:before {
  content: "\20ac";
}

.glyphicon-minus:before {
  content: "\2212";
}

.glyphicon-cloud:before {
  content: "\2601";
}

.glyphicon-envelope:before {
  content: "\2709";
}

.glyphicon-pencil:before {
  content: "\270f";
}

.glyphicon-glass:before {
  content: "\e001";
}

.glyphicon-music:before {
  content: "\e002";
}

.glyphicon-search:before {
  content: "\e003";
}

.glyphicon-heart:before {
  content: "\e005";
}

.glyphicon-star:before {
  content: "\e006";
}

.glyphicon-star-empty:before {
  content: "\e007";
}

.glyphicon-user:before {
  content: "\e008";
}

.glyphicon-film:before {
  content: "\e009";
}

.glyphicon-th-large:before {
  content: "\e010";
}

.glyphicon-th:before {
  content: "\e011";
}

.glyphicon-th-list:before {
  content: "\e012";
}

.glyphicon-ok:before {
  content: "\e013";
}

.glyphicon-remove:before {
  content: "\e014";
}

.glyphicon-zoom-in:before {
  content: "\e015";
}

.glyphicon-zoom-out:before {
  content: "\e016";
}

.glyphicon-off:before {
  content: "\e017";
}

.glyphicon-signal:before {
  content: "\e018";
}

.glyphicon-cog:before {
  content: "\e019";
}

.glyphicon-trash:before {
  content: "\e020";
}

.glyphicon-home:before {
  content: "\e021";
}

.glyphicon-file:before {
  content: "\e022";
}

.glyphicon-time:before {
  content: "\e023";
}

.glyphicon-road:before {
  content: "\e024";
}

.glyphicon-download-alt:before {
  content: "\e025";
}

.glyphicon-download:before {
  content: "\e026";
}

.glyphicon-upload:before {
  content: "\e027";
}

.glyphicon-inbox:before {
  content: "\e028";
}

.glyphicon-play-circle:before {
  content: "\e029";
}

.glyphicon-repeat:before {
  content: "\e030";
}

.glyphicon-refresh:before {
  content: "\e031";
}

.glyphicon-list-alt:before {
  content: "\e032";
}

.glyphicon-lock:before {
  content: "\e033";
}

.glyphicon-flag:before {
  content: "\e034";
}

.glyphicon-headphones:before {
  content: "\e035";
}

.glyphicon-volume-off:before {
  content: "\e036";
}

.glyphicon-volume-down:before {
  content: "\e037";
}

.glyphicon-volume-up:before {
  content: "\e038";
}

.glyphicon-qrcode:before {
  content: "\e039";
}

.glyphicon-barcode:before {
  content: "\e040";
}

.glyphicon-tag:before {
  content: "\e041";
}

.glyphicon-tags:before {
  content: "\e042";
}

.glyphicon-book:before {
  content: "\e043";
}

.glyphicon-bookmark:before {
  content: "\e044";
}

.glyphicon-print:before {
  content: "\e045";
}

.glyphicon-camera:before {
  content: "\e046";
}

.glyphicon-font:before {
  content: "\e047";
}

.glyphicon-bold:before {
  content: "\e048";
}

.glyphicon-italic:before {
  content: "\e049";
}

.glyphicon-text-height:before {
  content: "\e050";
}

.glyphicon-text-width:before {
  content: "\e051";
}

.glyphicon-align-left:before {
  content: "\e052";
}

.glyphicon-align-center:before {
  content: "\e053";
}

.glyphicon-align-right:before {
  content: "\e054";
}

.glyphicon-align-justify:before {
  content: "\e055";
}

.glyphicon-list:before {
  content: "\e056";
}

.glyphicon-indent-left:before {
  content: "\e057";
}

.glyphicon-indent-right:before {
  content: "\e058";
}

.glyphicon-facetime-video:before {
  content: "\e059";
}

.glyphicon-picture:before {
  content: "\e060";
}

.glyphicon-map-marker:before {
  content: "\e062";
}

.glyphicon-adjust:before {
  content: "\e063";
}

.glyphicon-tint:before {
  content: "\e064";
}

.glyphicon-edit:before {
  content: "\e065";
}

.glyphicon-share:before {
  content: "\e066";
}

.glyphicon-check:before {
  content: "\e067";
}

.glyphicon-move:before {
  content: "\e068";
}

.glyphicon-step-backward:before {
  content: "\e069";
}

.glyphicon-fast-backward:before {
  content: "\e070";
}

.glyphicon-backward:before {
  content: "\e071";
}

.glyphicon-play:before {
  content: "\e072";
}

.glyphicon-pause:before {
  content: "\e073";
}

.glyphicon-stop:before {
  content: "\e074";
}

.glyphicon-forward:before {
  content: "\e075";
}

.glyphicon-fast-forward:before {
  content: "\e076";
}

.glyphicon-step-forward:before {
  content: "\e077";
}

.glyphicon-eject:before {
  content: "\e078";
}

.glyphicon-chevron-left:before {
  content: "\e079";
}

.glyphicon-chevron-right:before {
  content: "\e080";
}

.glyphicon-plus-sign:before {
  content: "\e081";
}

.glyphicon-minus-sign:before {
  content: "\e082";
}

.glyphicon-remove-sign:before {
  content: "\e083";
}

.glyphicon-ok-sign:before {
  content: "\e084";
}

.glyphicon-question-sign:before {
  content: "\e085";
}

.glyphicon-info-sign:before {
  content: "\e086";
}

.glyphicon-screenshot:before {
  content: "\e087";
}

.glyphicon-remove-circle:before {
  content: "\e088";
}

.glyphicon-ok-circle:before {
  content: "\e089";
}

.glyphicon-ban-circle:before {
  content: "\e090";
}

.glyphicon-arrow-left:before {
  content: "\e091";
}

.glyphicon-arrow-right:before {
  content: "\e092";
}

.glyphicon-arrow-up:before {
  content: "\e093";
}

.glyphicon-arrow-down:before {
  content: "\e094";
}

.glyphicon-share-alt:before {
  content: "\e095";
}

.glyphicon-resize-full:before {
  content: "\e096";
}

.glyphicon-resize-small:before {
  content: "\e097";
}

.glyphicon-exclamation-sign:before {
  content: "\e101";
}

.glyphicon-gift:before {
  content: "\e102";
}

.glyphicon-leaf:before {
  content: "\e103";
}

.glyphicon-fire:before {
  content: "\e104";
}

.glyphicon-eye-open:before {
  content: "\e105";
}

.glyphicon-eye-close:before {
  content: "\e106";
}

.glyphicon-warning-sign:before {
  content: "\e107";
}

.glyphicon-plane:before {
  content: "\e108";
}

.glyphicon-calendar:before {
  content: "\e109";
}

.glyphicon-random:before {
  content: "\e110";
}

.glyphicon-comment:before {
  content: "\e111";
}

.glyphicon-magnet:before {
  content: "\e112";
}

.glyphicon-chevron-up:before {
  content: "\e113";
}

.glyphicon-chevron-down:before {
  content: "\e114";
}

.glyphicon-retweet:before {
  content: "\e115";
}

.glyphicon-shopping-cart:before {
  content: "\e116";
}

.glyphicon-folder-close:before {
  content: "\e117";
}

.glyphicon-folder-open:before {
  content: "\e118";
}

.glyphicon-resize-vertical:before {
  content: "\e119";
}

.glyphicon-resize-horizontal:before {
  content: "\e120";
}

.glyphicon-hdd:before {
  content: "\e121";
}

.glyphicon-bullhorn:before {
  content: "\e122";
}

.glyphicon-bell:before {
  content: "\e123";
}

.glyphicon-certificate:before {
  content: "\e124";
}

.glyphicon-thumbs-up:before {
  content: "\e125";
}

.glyphicon-thumbs-down:before {
  content: "\e126";
}

.glyphicon-hand-right:before {
  content: "\e127";
}

.glyphicon-hand-left:before {
  content: "\e128";
}

.glyphicon-hand-up:before {
  content: "\e129";
}

.glyphicon-hand-down:before {
  content: "\e130";
}

.glyphicon-circle-arrow-right:before {
  content: "\e131";
}

.glyphicon-circle-arrow-left:before {
  content: "\e132";
}

.glyphicon-circle-arrow-up:before {
  content: "\e133";
}

.glyphicon-circle-arrow-down:before {
  content: "\e134";
}

.glyphicon-globe:before {
  content: "\e135";
}

.glyphicon-wrench:before {
  content: "\e136";
}

.glyphicon-tasks:before {
  content: "\e137";
}

.glyphicon-filter:before {
  content: "\e138";
}

.glyphicon-briefcase:before {
  content: "\e139";
}

.glyphicon-fullscreen:before {
  content: "\e140";
}

.glyphicon-dashboard:before {
  content: "\e141";
}

.glyphicon-paperclip:before {
  content: "\e142";
}

.glyphicon-heart-empty:before {
  content: "\e143";
}

.glyphicon-link:before {
  content: "\e144";
}

.glyphicon-phone:before {
  content: "\e145";
}

.glyphicon-pushpin:before {
  content: "\e146";
}

.glyphicon-usd:before {
  content: "\e148";
}

.glyphicon-gbp:before {
  content: "\e149";
}

.glyphicon-sort:before {
  content: "\e150";
}

.glyphicon-sort-by-alphabet:before {
  content: "\e151";
}

.glyphicon-sort-by-alphabet-alt:before {
  content: "\e152";
}

.glyphicon-sort-by-order:before {
  content: "\e153";
}

.glyphicon-sort-by-order-alt:before {
  content: "\e154";
}

.glyphicon-sort-by-attributes:before {
  content: "\e155";
}

.glyphicon-sort-by-attributes-alt:before {
  content: "\e156";
}

.glyphicon-unchecked:before {
  content: "\e157";
}

.glyphicon-expand:before {
  content: "\e158";
}

.glyphicon-collapse-down:before {
  content: "\e159";
}

.glyphicon-collapse-up:before {
  content: "\e160";
}

.glyphicon-log-in:before {
  content: "\e161";
}

.glyphicon-flash:before {
  content: "\e162";
}

.glyphicon-log-out:before {
  content: "\e163";
}

.glyphicon-new-window:before {
  content: "\e164";
}

.glyphicon-record:before {
  content: "\e165";
}

.glyphicon-save:before {
  content: "\e166";
}

.glyphicon-open:before {
  content: "\e167";
}

.glyphicon-saved:before {
  content: "\e168";
}

.glyphicon-import:before {
  content: "\e169";
}

.glyphicon-export:before {
  content: "\e170";
}

.glyphicon-send:before {
  content: "\e171";
}

.glyphicon-floppy-disk:before {
  content: "\e172";
}

.glyphicon-floppy-saved:before {
  content: "\e173";
}

.glyphicon-floppy-remove:before {
  content: "\e174";
}

.glyphicon-floppy-save:before {
  content: "\e175";
}

.glyphicon-floppy-open:before {
  content: "\e176";
}

.glyphicon-credit-card:before {
  content: "\e177";
}

.glyphicon-transfer:before {
  content: "\e178";
}

.glyphicon-cutlery:before {
  content: "\e179";
}

.glyphicon-header:before {
  content: "\e180";
}

.glyphicon-compressed:before {
  content: "\e181";
}

.glyphicon-earphone:before {
  content: "\e182";
}

.glyphicon-phone-alt:before {
  content: "\e183";
}

.glyphicon-tower:before {
  content: "\e184";
}

.glyphicon-stats:before {
  content: "\e185";
}

.glyphicon-sd-video:before {
  content: "\e186";
}

.glyphicon-hd-video:before {
  content: "\e187";
}

.glyphicon-subtitles:before {
  content: "\e188";
}

.glyphicon-sound-stereo:before {
  content: "\e189";
}

.glyphicon-sound-dolby:before {
  content: "\e190";
}

.glyphicon-sound-5-1:before {
  content: "\e191";
}

.glyphicon-sound-6-1:before {
  content: "\e192";
}

.glyphicon-sound-7-1:before {
  content: "\e193";
}

.glyphicon-copyright-mark:before {
  content: "\e194";
}

.glyphicon-registration-mark:before {
  content: "\e195";
}

.glyphicon-cloud-download:before {
  content: "\e197";
}

.glyphicon-cloud-upload:before {
  content: "\e198";
}

.glyphicon-tree-conifer:before {
  content: "\e199";
}

.glyphicon-tree-deciduous:before {
  content: "\e200";
}

* {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

*:before,
*:after {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

html {
  font-size: 10px;
  -webkit-tap-highlight-color: transparent;
}

body {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 14px;
  line-height: 1.428571429;
  color: #333333;
  background-color: #fff;
}

input,
button,
select,
textarea {
  font-family: inherit;
  font-size: inherit;
  line-height: inherit;
}

a {
  color: #428bca;
  text-decoration: none;
}
a:hover, a:focus {
  color: #2a6496;
  text-decoration: underline;
}
a:focus {
  outline: thin dotted;
  outline: 5px auto -webkit-focus-ring-color;
  outline-offset: -2px;
}

figure {
  margin: 0;
}

img {
  vertical-align: middle;
}

.img-responsive {
  display: block;
  width: 100% \9;
  max-width: 100%;
  height: auto;
}

.img-rounded {
  border-radius: 6px;
}

.img-thumbnail {
  padding: 4px;
  line-height: 1.428571429;
  background-color: #fff;
  border: 1px solid #ddd;
  border-radius: 4px;
  -webkit-transition: all 0.2s ease-in-out;
  -o-transition: all 0.2s ease-in-out;
  transition: all 0.2s ease-in-out;
  display: inline-block;
  width: 100% \9;
  max-width: 100%;
  height: auto;
}

.img-circle {
  border-radius: 50%;
}

hr {
  margin-top: 20px;
  margin-bottom: 20px;
  border: 0;
  border-top: 1px solid #eeeeee;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
}

.sr-only-focusable:active, .sr-only-focusable:focus {
  position: static;
  width: auto;
  height: auto;
  margin: 0;
  overflow: visible;
  clip: auto;
}

h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
  font-family: inherit;
  font-weight: 500;
  line-height: 1.1;
  color: inherit;
}
h1 small,
h1 .small, h2 small,
h2 .small, h3 small,
h3 .small, h4 small,
h4 .small, h5 small,
h5 .small, h6 small,
h6 .small,
.h1 small,
.h1 .small, .h2 small,
.h2 .small, .h3 small,
.h3 .small, .h4 small,
.h4 .small, .h5 small,
.h5 .small, .h6 small,
.h6 .small {
  font-weight: normal;
  line-height: 1;
  color: #777777;
}

h1, .h1,
h2, .h2,
h3, .h3 {
  margin-top: 20px;
  margin-bottom: 10px;
}
h1 small,
h1 .small, .h1 small,
.h1 .small,
h2 small,
h2 .small, .h2 small,
.h2 .small,
h3 small,
h3 .small, .h3 small,
.h3 .small {
  font-size: 65%;
}

h4, .h4,
h5, .h5,
h6, .h6 {
  margin-top: 10px;
  margin-bottom: 10px;
}
h4 small,
h4 .small, .h4 small,
.h4 .small,
h5 small,
h5 .small, .h5 small,
.h5 .small,
h6 small,
h6 .small, .h6 small,
.h6 .small {
  font-size: 75%;
}

h1, .h1 {
  font-size: 36px;
}

h2, .h2 {
  font-size: 30px;
}

h3, .h3 {
  font-size: 24px;
}

h4, .h4 {
  font-size: 18px;
}

h5, .h5 {
  font-size: 14px;
}

h6, .h6 {
  font-size: 12px;
}

p {
  margin: 0 0 10px;
}

.lead {
  margin-bottom: 20px;
  font-size: 16px;
  font-weight: 300;
  line-height: 1.4;
}
@media (min-width: 768px) {
  .lead {
    font-size: 21px;
  }
}

small,
.small {
  font-size: 85%;
}

cite {
  font-style: normal;
}

mark,
.mark {
  background-color: #fcf8e3;
  padding: .2em;
}

.text-left {
  text-align: left;
}

.text-right {
  text-align: right;
}

.text-center {
  text-align: center;
}

.text-justify {
  text-align: justify;
}

.text-nowrap {
  white-space: nowrap;
}

.text-lowercase {
  text-transform: lowercase;
}

.text-uppercase {
  text-transform: uppercase;
}

.text-capitalize {
  text-transform: capitalize;
}

.text-muted {
  color: #777777;
}

.text-primary {
  color: #428bca;
}

a.text-primary:hover {
  color: #3071a9;
}

.text-success {
  color: #3c763d;
}

a.text-success:hover {
  color: #2b542c;
}

.text-info {
  color: #31708f;
}

a.text-info:hover {
  color: #245269;
}

.text-warning {
  color: #8a6d3b;
}

a.text-warning:hover {
  color: #66512c;
}

.text-danger {
  color: #a94442;
}

a.text-danger:hover {
  color: #843534;
}

.bg-primary {
  color: #fff;
}

.bg-primary {
  background-color: #428bca;
}

a.bg-primary:hover {
  background-color: #3071a9;
}

.bg-success {
  background-color: #dff0d8;
}

a.bg-success:hover {
  background-color: #c1e2b3;
}

.bg-info {
  background-color: #d9edf7;
}

a.bg-info:hover {
  background-color: #afd9ee;
}

.bg-warning {
  background-color: #fcf8e3;
}

a.bg-warning:hover {
  background-color: #f7ecb5;
}

.bg-danger {
  background-color: #f2dede;
}

a.bg-danger:hover {
  background-color: #e4b9b9;
}

.page-header {
  padding-bottom: 9px;
  margin: 40px 0 20px;
  border-bottom: 1px solid #eeeeee;
}

ul,
ol {
  margin-top: 0;
  margin-bottom: 10px;
}
ul ul,
ul ol,
ol ul,
ol ol {
  margin-bottom: 0;
}

.list-unstyled, .list-inline {
  padding-left: 0;
  list-style: none;
}

.list-inline {
  margin-left: -5px;
}
.list-inline > li {
  display: inline-block;
  padding-left: 5px;
  padding-right: 5px;
}

dl {
  margin-top: 0;
  margin-bottom: 20px;
}

dt,
dd {
  line-height: 1.428571429;
}

dt {
  font-weight: bold;
}

dd {
  margin-left: 0;
}

.dl-horizontal dd:before, .dl-horizontal dd:after {
  content: " ";
  display: table;
}
.dl-horizontal dd:after {
  clear: both;
}
@media (min-width: 768px) {
  .dl-horizontal dt {
    float: left;
    width: 160px;
    clear: left;
    text-align: right;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .dl-horizontal dd {
    margin-left: 180px;
  }
}

abbr[title],
abbr[data-original-title] {
  cursor: help;
  border-bottom: 1px dotted #777777;
}

.initialism {
  font-size: 90%;
  text-transform: uppercase;
}

blockquote {
  padding: 10px 20px;
  margin: 0 0 20px;
  font-size: 17.5px;
  border-left: 5px solid #eeeeee;
}
blockquote p:last-child,
blockquote ul:last-child,
blockquote ol:last-child {
  margin-bottom: 0;
}
blockquote footer,
blockquote small,
blockquote .small {
  display: block;
  font-size: 80%;
  line-height: 1.428571429;
  color: #777777;
}
blockquote footer:before,
blockquote small:before,
blockquote .small:before {
  content: '\2014 \00A0';
}

.blockquote-reverse,
blockquote.pull-right {
  padding-right: 15px;
  padding-left: 0;
  border-right: 5px solid #eeeeee;
  border-left: 0;
  text-align: right;
}
.blockquote-reverse footer:before,
.blockquote-reverse small:before,
.blockquote-reverse .small:before,
blockquote.pull-right footer:before,
blockquote.pull-right small:before,
blockquote.pull-right .small:before {
  content: '';
}
.blockquote-reverse footer:after,
.blockquote-reverse small:after,
.blockquote-reverse .small:after,
blockquote.pull-right footer:after,
blockquote.pull-right small:after,
blockquote.pull-right .small:after {
  content: '\00A0 \2014';
}

blockquote:before,
blockquote:after {
  content: "";
}

address {
  margin-bottom: 20px;
  font-style: normal;
  line-height: 1.428571429;
}

code,
kbd,
pre,
samp {
  font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
}

code {
  padding: 2px 4px;
  font-size: 90%;
  color: #c7254e;
  background-color: #f9f2f4;
  border-radius: 4px;
}

kbd {
  padding: 2px 4px;
  font-size: 90%;
  color: #fff;
  background-color: #333;
  border-radius: 3px;
  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);
}
kbd kbd {
  padding: 0;
  font-size: 100%;
  box-shadow: none;
}

pre {
  display: block;
  padding: 9.5px;
  margin: 0 0 10px;
  font-size: 13px;
  line-height: 1.428571429;
  word-break: break-all;
  word-wrap: break-word;
  color: #333333;
  background-color: #f5f5f5;
  border: 1px solid #ccc;
  border-radius: 4px;
}
pre code {
  padding: 0;
  font-size: inherit;
  color: inherit;
  white-space: pre-wrap;
  background-color: transparent;
  border-radius: 0;
}

.pre-scrollable {
  max-height: 340px;
  overflow-y: scroll;
}

.container {
  margin-right: auto;
  margin-left: auto;
  padding-left: 15px;
  padding-right: 15px;
}
.container:before, .container:after {
  content: " ";
  display: table;
}
.container:after {
  clear: both;
}
@media (min-width: 768px) {
  .container {
    width: 750px;
  }
}
@media (min-width: 992px) {
  .container {
    width: 970px;
  }
}
@media (min-width: 1200px) {
  .container {
    width: 1170px;
  }
}

.container-fluid {
  margin-right: auto;
  margin-left: auto;
  padding-left: 15px;
  padding-right: 15px;
}
.container-fluid:before, .container-fluid:after {
  content: " ";
  display: table;
}
.container-fluid:after {
  clear: both;
}

.row {
  margin-left: -15px;
  margin-right: -15px;
}
.row:before, .row:after {
  content: " ";
  display: table;
}
.row:after {
  clear: both;
}

.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {
  position: relative;
  min-height: 1px;
  padding-left: 15px;
  padding-right: 15px;
}

.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {
  float: left;
}

.col-xs-1 {
  width: 8.3333333333%;
}

.col-xs-2 {
  width: 16.6666666667%;
}

.col-xs-3 {
  width: 25%;
}

.col-xs-4 {
  width: 33.3333333333%;
}

.col-xs-5 {
  width: 41.6666666667%;
}

.col-xs-6 {
  width: 50%;
}

.col-xs-7 {
  width: 58.3333333333%;
}

.col-xs-8 {
  width: 66.6666666667%;
}

.col-xs-9 {
  width: 75%;
}

.col-xs-10 {
  width: 83.3333333333%;
}

.col-xs-11 {
  width: 91.6666666667%;
}

.col-xs-12 {
  width: 100%;
}

.col-xs-pull-0 {
  right: auto;
}

.col-xs-pull-1 {
  right: 8.3333333333%;
}

.col-xs-pull-2 {
  right: 16.6666666667%;
}

.col-xs-pull-3 {
  right: 25%;
}

.col-xs-pull-4 {
  right: 33.3333333333%;
}

.col-xs-pull-5 {
  right: 41.6666666667%;
}

.col-xs-pull-6 {
  right: 50%;
}

.col-xs-pull-7 {
  right: 58.3333333333%;
}

.col-xs-pull-8 {
  right: 66.6666666667%;
}

.col-xs-pull-9 {
  right: 75%;
}

.col-xs-pull-10 {
  right: 83.3333333333%;
}

.col-xs-pull-11 {
  right: 91.6666666667%;
}

.col-xs-pull-12 {
  right: 100%;
}

.col-xs-push-0 {
  left: auto;
}

.col-xs-push-1 {
  left: 8.3333333333%;
}

.col-xs-push-2 {
  left: 16.6666666667%;
}

.col-xs-push-3 {
  left: 25%;
}

.col-xs-push-4 {
  left: 33.3333333333%;
}

.col-xs-push-5 {
  left: 41.6666666667%;
}

.col-xs-push-6 {
  left: 50%;
}

.col-xs-push-7 {
  left: 58.3333333333%;
}

.col-xs-push-8 {
  left: 66.6666666667%;
}

.col-xs-push-9 {
  left: 75%;
}

.col-xs-push-10 {
  left: 83.3333333333%;
}

.col-xs-push-11 {
  left: 91.6666666667%;
}

.col-xs-push-12 {
  left: 100%;
}

.col-xs-offset-0 {
  margin-left: 0%;
}

.col-xs-offset-1 {
  margin-left: 8.3333333333%;
}

.col-xs-offset-2 {
  margin-left: 16.6666666667%;
}

.col-xs-offset-3 {
  margin-left: 25%;
}

.col-xs-offset-4 {
  margin-left: 33.3333333333%;
}

.col-xs-offset-5 {
  margin-left: 41.6666666667%;
}

.col-xs-offset-6 {
  margin-left: 50%;
}

.col-xs-offset-7 {
  margin-left: 58.3333333333%;
}

.col-xs-offset-8 {
  margin-left: 66.6666666667%;
}

.col-xs-offset-9 {
  margin-left: 75%;
}

.col-xs-offset-10 {
  margin-left: 83.3333333333%;
}

.col-xs-offset-11 {
  margin-left: 91.6666666667%;
}

.col-xs-offset-12 {
  margin-left: 100%;
}

@media (min-width: 768px) {
  .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {
    float: left;
  }

  .col-sm-1 {
    width: 8.3333333333%;
  }

  .col-sm-2 {
    width: 16.6666666667%;
  }

  .col-sm-3 {
    width: 25%;
  }

  .col-sm-4 {
    width: 33.3333333333%;
  }

  .col-sm-5 {
    width: 41.6666666667%;
  }

  .col-sm-6 {
    width: 50%;
  }

  .col-sm-7 {
    width: 58.3333333333%;
  }

  .col-sm-8 {
    width: 66.6666666667%;
  }

  .col-sm-9 {
    width: 75%;
  }

  .col-sm-10 {
    width: 83.3333333333%;
  }

  .col-sm-11 {
    width: 91.6666666667%;
  }

  .col-sm-12 {
    width: 100%;
  }

  .col-sm-pull-0 {
    right: auto;
  }

  .col-sm-pull-1 {
    right: 8.3333333333%;
  }

  .col-sm-pull-2 {
    right: 16.6666666667%;
  }

  .col-sm-pull-3 {
    right: 25%;
  }

  .col-sm-pull-4 {
    right: 33.3333333333%;
  }

  .col-sm-pull-5 {
    right: 41.6666666667%;
  }

  .col-sm-pull-6 {
    right: 50%;
  }

  .col-sm-pull-7 {
    right: 58.3333333333%;
  }

  .col-sm-pull-8 {
    right: 66.6666666667%;
  }

  .col-sm-pull-9 {
    right: 75%;
  }

  .col-sm-pull-10 {
    right: 83.3333333333%;
  }

  .col-sm-pull-11 {
    right: 91.6666666667%;
  }

  .col-sm-pull-12 {
    right: 100%;
  }

  .col-sm-push-0 {
    left: auto;
  }

  .col-sm-push-1 {
    left: 8.3333333333%;
  }

  .col-sm-push-2 {
    left: 16.6666666667%;
  }

  .col-sm-push-3 {
    left: 25%;
  }

  .col-sm-push-4 {
    left: 33.3333333333%;
  }

  .col-sm-push-5 {
    left: 41.6666666667%;
  }

  .col-sm-push-6 {
    left: 50%;
  }

  .col-sm-push-7 {
    left: 58.3333333333%;
  }

  .col-sm-push-8 {
    left: 66.6666666667%;
  }

  .col-sm-push-9 {
    left: 75%;
  }

  .col-sm-push-10 {
    left: 83.3333333333%;
  }

  .col-sm-push-11 {
    left: 91.6666666667%;
  }

  .col-sm-push-12 {
    left: 100%;
  }

  .col-sm-offset-0 {
    margin-left: 0%;
  }

  .col-sm-offset-1 {
    margin-left: 8.3333333333%;
  }

  .col-sm-offset-2 {
    margin-left: 16.6666666667%;
  }

  .col-sm-offset-3 {
    margin-left: 25%;
  }

  .col-sm-offset-4 {
    margin-left: 33.3333333333%;
  }

  .col-sm-offset-5 {
    margin-left: 41.6666666667%;
  }

  .col-sm-offset-6 {
    margin-left: 50%;
  }

  .col-sm-offset-7 {
    margin-left: 58.3333333333%;
  }

  .col-sm-offset-8 {
    margin-left: 66.6666666667%;
  }

  .col-sm-offset-9 {
    margin-left: 75%;
  }

  .col-sm-offset-10 {
    margin-left: 83.3333333333%;
  }

  .col-sm-offset-11 {
    margin-left: 91.6666666667%;
  }

  .col-sm-offset-12 {
    margin-left: 100%;
  }
}
@media (min-width: 992px) {
  .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {
    float: left;
  }

  .col-md-1 {
    width: 8.3333333333%;
  }

  .col-md-2 {
    width: 16.6666666667%;
  }

  .col-md-3 {
    width: 25%;
  }

  .col-md-4 {
    width: 33.3333333333%;
  }

  .col-md-5 {
    width: 41.6666666667%;
  }

  .col-md-6 {
    width: 50%;
  }

  .col-md-7 {
    width: 58.3333333333%;
  }

  .col-md-8 {
    width: 66.6666666667%;
  }

  .col-md-9 {
    width: 75%;
  }

  .col-md-10 {
    width: 83.3333333333%;
  }

  .col-md-11 {
    width: 91.6666666667%;
  }

  .col-md-12 {
    width: 100%;
  }

  .col-md-pull-0 {
    right: auto;
  }

  .col-md-pull-1 {
    right: 8.3333333333%;
  }

  .col-md-pull-2 {
    right: 16.6666666667%;
  }

  .col-md-pull-3 {
    right: 25%;
  }

  .col-md-pull-4 {
    right: 33.3333333333%;
  }

  .col-md-pull-5 {
    right: 41.6666666667%;
  }

  .col-md-pull-6 {
    right: 50%;
  }

  .col-md-pull-7 {
    right: 58.3333333333%;
  }

  .col-md-pull-8 {
    right: 66.6666666667%;
  }

  .col-md-pull-9 {
    right: 75%;
  }

  .col-md-pull-10 {
    right: 83.3333333333%;
  }

  .col-md-pull-11 {
    right: 91.6666666667%;
  }

  .col-md-pull-12 {
    right: 100%;
  }

  .col-md-push-0 {
    left: auto;
  }

  .col-md-push-1 {
    left: 8.3333333333%;
  }

  .col-md-push-2 {
    left: 16.6666666667%;
  }

  .col-md-push-3 {
    left: 25%;
  }

  .col-md-push-4 {
    left: 33.3333333333%;
  }

  .col-md-push-5 {
    left: 41.6666666667%;
  }

  .col-md-push-6 {
    left: 50%;
  }

  .col-md-push-7 {
    left: 58.3333333333%;
  }

  .col-md-push-8 {
    left: 66.6666666667%;
  }

  .col-md-push-9 {
    left: 75%;
  }

  .col-md-push-10 {
    left: 83.3333333333%;
  }

  .col-md-push-11 {
    left: 91.6666666667%;
  }

  .col-md-push-12 {
    left: 100%;
  }

  .col-md-offset-0 {
    margin-left: 0%;
  }

  .col-md-offset-1 {
    margin-left: 8.3333333333%;
  }

  .col-md-offset-2 {
    margin-left: 16.6666666667%;
  }

  .col-md-offset-3 {
    margin-left: 25%;
  }

  .col-md-offset-4 {
    margin-left: 33.3333333333%;
  }

  .col-md-offset-5 {
    margin-left: 41.6666666667%;
  }

  .col-md-offset-6 {
    margin-left: 50%;
  }

  .col-md-offset-7 {
    margin-left: 58.3333333333%;
  }

  .col-md-offset-8 {
    margin-left: 66.6666666667%;
  }

  .col-md-offset-9 {
    margin-left: 75%;
  }

  .col-md-offset-10 {
    margin-left: 83.3333333333%;
  }

  .col-md-offset-11 {
    margin-left: 91.6666666667%;
  }

  .col-md-offset-12 {
    margin-left: 100%;
  }
}
@media (min-width: 1200px) {
  .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {
    float: left;
  }

  .col-lg-1 {
    width: 8.3333333333%;
  }

  .col-lg-2 {
    width: 16.6666666667%;
  }

  .col-lg-3 {
    width: 25%;
  }

  .col-lg-4 {
    width: 33.3333333333%;
  }

  .col-lg-5 {
    width: 41.6666666667%;
  }

  .col-lg-6 {
    width: 50%;
  }

  .col-lg-7 {
    width: 58.3333333333%;
  }

  .col-lg-8 {
    width: 66.6666666667%;
  }

  .col-lg-9 {
    width: 75%;
  }

  .col-lg-10 {
    width: 83.3333333333%;
  }

  .col-lg-11 {
    width: 91.6666666667%;
  }

  .col-lg-12 {
    width: 100%;
  }

  .col-lg-pull-0 {
    right: auto;
  }

  .col-lg-pull-1 {
    right: 8.3333333333%;
  }

  .col-lg-pull-2 {
    right: 16.6666666667%;
  }

  .col-lg-pull-3 {
    right: 25%;
  }

  .col-lg-pull-4 {
    right: 33.3333333333%;
  }

  .col-lg-pull-5 {
    right: 41.6666666667%;
  }

  .col-lg-pull-6 {
    right: 50%;
  }

  .col-lg-pull-7 {
    right: 58.3333333333%;
  }

  .col-lg-pull-8 {
    right: 66.6666666667%;
  }

  .col-lg-pull-9 {
    right: 75%;
  }

  .col-lg-pull-10 {
    right: 83.3333333333%;
  }

  .col-lg-pull-11 {
    right: 91.6666666667%;
  }

  .col-lg-pull-12 {
    right: 100%;
  }

  .col-lg-push-0 {
    left: auto;
  }

  .col-lg-push-1 {
    left: 8.3333333333%;
  }

  .col-lg-push-2 {
    left: 16.6666666667%;
  }

  .col-lg-push-3 {
    left: 25%;
  }

  .col-lg-push-4 {
    left: 33.3333333333%;
  }

  .col-lg-push-5 {
    left: 41.6666666667%;
  }

  .col-lg-push-6 {
    left: 50%;
  }

  .col-lg-push-7 {
    left: 58.3333333333%;
  }

  .col-lg-push-8 {
    left: 66.6666666667%;
  }

  .col-lg-push-9 {
    left: 75%;
  }

  .col-lg-push-10 {
    left: 83.3333333333%;
  }

  .col-lg-push-11 {
    left: 91.6666666667%;
  }

  .col-lg-push-12 {
    left: 100%;
  }

  .col-lg-offset-0 {
    margin-left: 0%;
  }

  .col-lg-offset-1 {
    margin-left: 8.3333333333%;
  }

  .col-lg-offset-2 {
    margin-left: 16.6666666667%;
  }

  .col-lg-offset-3 {
    margin-left: 25%;
  }

  .col-lg-offset-4 {
    margin-left: 33.3333333333%;
  }

  .col-lg-offset-5 {
    margin-left: 41.6666666667%;
  }

  .col-lg-offset-6 {
    margin-left: 50%;
  }

  .col-lg-offset-7 {
    margin-left: 58.3333333333%;
  }

  .col-lg-offset-8 {
    margin-left: 66.6666666667%;
  }

  .col-lg-offset-9 {
    margin-left: 75%;
  }

  .col-lg-offset-10 {
    margin-left: 83.3333333333%;
  }

  .col-lg-offset-11 {
    margin-left: 91.6666666667%;
  }

  .col-lg-offset-12 {
    margin-left: 100%;
  }
}
table {
  background-color: transparent;
}

th {
  text-align: left;
}

.table {
  width: 100%;
  max-width: 100%;
  margin-bottom: 20px;
}
.table > thead > tr > th,
.table > thead > tr > td,
.table > tbody > tr > th,
.table > tbody > tr > td,
.table > tfoot > tr > th,
.table > tfoot > tr > td {
  padding: 8px;
  line-height: 1.428571429;
  vertical-align: top;
  border-top: 1px solid #ddd;
}
.table > thead > tr > th {
  vertical-align: bottom;
  border-bottom: 2px solid #ddd;
}
.table > caption + thead > tr:first-child > th,
.table > caption + thead > tr:first-child > td,
.table > colgroup + thead > tr:first-child > th,
.table > colgroup + thead > tr:first-child > td,
.table > thead:first-child > tr:first-child > th,
.table > thead:first-child > tr:first-child > td {
  border-top: 0;
}
.table > tbody + tbody {
  border-top: 2px solid #ddd;
}
.table .table {
  background-color: #fff;
}

.table-condensed > thead > tr > th,
.table-condensed > thead > tr > td,
.table-condensed > tbody > tr > th,
.table-condensed > tbody > tr > td,
.table-condensed > tfoot > tr > th,
.table-condensed > tfoot > tr > td {
  padding: 5px;
}

.table-bordered {
  border: 1px solid #ddd;
}
.table-bordered > thead > tr > th,
.table-bordered > thead > tr > td,
.table-bordered > tbody > tr > th,
.table-bordered > tbody > tr > td,
.table-bordered > tfoot > tr > th,
.table-bordered > tfoot > tr > td {
  border: 1px solid #ddd;
}
.table-bordered > thead > tr > th,
.table-bordered > thead > tr > td {
  border-bottom-width: 2px;
}

.table-striped > tbody > tr:nth-child(odd) > td,
.table-striped > tbody > tr:nth-child(odd) > th {
  background-color: #f9f9f9;
}

.table-hover > tbody > tr:hover > td,
.table-hover > tbody > tr:hover > th {
  background-color: #f5f5f5;
}

table col[class*="col-"] {
  position: static;
  float: none;
  display: table-column;
}

table td[class*="col-"],
table th[class*="col-"] {
  position: static;
  float: none;
  display: table-cell;
}

.table > thead > tr > td.active,
.table > thead > tr > th.active, .table > thead > tr.active > td, .table > thead > tr.active > th,
.table > tbody > tr > td.active,
.table > tbody > tr > th.active,
.table > tbody > tr.active > td,
.table > tbody > tr.active > th,
.table > tfoot > tr > td.active,
.table > tfoot > tr > th.active,
.table > tfoot > tr.active > td,
.table > tfoot > tr.active > th {
  background-color: #f5f5f5;
}

.table-hover > tbody > tr > td.active:hover,
.table-hover > tbody > tr > th.active:hover, .table-hover > tbody > tr.active:hover > td, .table-hover > tbody > tr:hover > .active, .table-hover > tbody > tr.active:hover > th {
  background-color: #e8e8e8;
}

.table > thead > tr > td.success,
.table > thead > tr > th.success, .table > thead > tr.success > td, .table > thead > tr.success > th,
.table > tbody > tr > td.success,
.table > tbody > tr > th.success,
.table > tbody > tr.success > td,
.table > tbody > tr.success > th,
.table > tfoot > tr > td.success,
.table > tfoot > tr > th.success,
.table > tfoot > tr.success > td,
.table > tfoot > tr.success > th {
  background-color: #dff0d8;
}

.table-hover > tbody > tr > td.success:hover,
.table-hover > tbody > tr > th.success:hover, .table-hover > tbody > tr.success:hover > td, .table-hover > tbody > tr:hover > .success, .table-hover > tbody > tr.success:hover > th {
  background-color: #d0e9c6;
}

.table > thead > tr > td.info,
.table > thead > tr > th.info, .table > thead > tr.info > td, .table > thead > tr.info > th,
.table > tbody > tr > td.info,
.table > tbody > tr > th.info,
.table > tbody > tr.info > td,
.table > tbody > tr.info > th,
.table > tfoot > tr > td.info,
.table > tfoot > tr > th.info,
.table > tfoot > tr.info > td,
.table > tfoot > tr.info > th {
  background-color: #d9edf7;
}

.table-hover > tbody > tr > td.info:hover,
.table-hover > tbody > tr > th.info:hover, .table-hover > tbody > tr.info:hover > td, .table-hover > tbody > tr:hover > .info, .table-hover > tbody > tr.info:hover > th {
  background-color: #c4e3f3;
}

.table > thead > tr > td.warning,
.table > thead > tr > th.warning, .table > thead > tr.warning > td, .table > thead > tr.warning > th,
.table > tbody > tr > td.warning,
.table > tbody > tr > th.warning,
.table > tbody > tr.warning > td,
.table > tbody > tr.warning > th,
.table > tfoot > tr > td.warning,
.table > tfoot > tr > th.warning,
.table > tfoot > tr.warning > td,
.table > tfoot > tr.warning > th {
  background-color: #fcf8e3;
}

.table-hover > tbody > tr > td.warning:hover,
.table-hover > tbody > tr > th.warning:hover, .table-hover > tbody > tr.warning:hover > td, .table-hover > tbody > tr:hover > .warning, .table-hover > tbody > tr.warning:hover > th {
  background-color: #faf2cc;
}

.table > thead > tr > td.danger,
.table > thead > tr > th.danger, .table > thead > tr.danger > td, .table > thead > tr.danger > th,
.table > tbody > tr > td.danger,
.table > tbody > tr > th.danger,
.table > tbody > tr.danger > td,
.table > tbody > tr.danger > th,
.table > tfoot > tr > td.danger,
.table > tfoot > tr > th.danger,
.table > tfoot > tr.danger > td,
.table > tfoot > tr.danger > th {
  background-color: #f2dede;
}

.table-hover > tbody > tr > td.danger:hover,
.table-hover > tbody > tr > th.danger:hover, .table-hover > tbody > tr.danger:hover > td, .table-hover > tbody > tr:hover > .danger, .table-hover > tbody > tr.danger:hover > th {
  background-color: #ebcccc;
}

@media screen and (max-width: 767px) {
  .table-responsive {
    width: 100%;
    margin-bottom: 15px;
    overflow-y: hidden;
    overflow-x: auto;
    -ms-overflow-style: -ms-autohiding-scrollbar;
    border: 1px solid #ddd;
    -webkit-overflow-scrolling: touch;
  }
  .table-responsive > .table {
    margin-bottom: 0;
  }
  .table-responsive > .table > thead > tr > th,
  .table-responsive > .table > thead > tr > td,
  .table-responsive > .table > tbody > tr > th,
  .table-responsive > .table > tbody > tr > td,
  .table-responsive > .table > tfoot > tr > th,
  .table-responsive > .table > tfoot > tr > td {
    white-space: nowrap;
  }
  .table-responsive > .table-bordered {
    border: 0;
  }
  .table-responsive > .table-bordered > thead > tr > th:first-child,
  .table-responsive > .table-bordered > thead > tr > td:first-child,
  .table-responsive > .table-bordered > tbody > tr > th:first-child,
  .table-responsive > .table-bordered > tbody > tr > td:first-child,
  .table-responsive > .table-bordered > tfoot > tr > th:first-child,
  .table-responsive > .table-bordered > tfoot > tr > td:first-child {
    border-left: 0;
  }
  .table-responsive > .table-bordered > thead > tr > th:last-child,
  .table-responsive > .table-bordered > thead > tr > td:last-child,
  .table-responsive > .table-bordered > tbody > tr > th:last-child,
  .table-responsive > .table-bordered > tbody > tr > td:last-child,
  .table-responsive > .table-bordered > tfoot > tr > th:last-child,
  .table-responsive > .table-bordered > tfoot > tr > td:last-child {
    border-right: 0;
  }
  .table-responsive > .table-bordered > tbody > tr:last-child > th,
  .table-responsive > .table-bordered > tbody > tr:last-child > td,
  .table-responsive > .table-bordered > tfoot > tr:last-child > th,
  .table-responsive > .table-bordered > tfoot > tr:last-child > td {
    border-bottom: 0;
  }
}

fieldset {
  padding: 0;
  margin: 0;
  border: 0;
  min-width: 0;
}

legend {
  display: block;
  width: 100%;
  padding: 0;
  margin-bottom: 20px;
  font-size: 21px;
  line-height: inherit;
  color: #333333;
  border: 0;
  border-bottom: 1px solid #e5e5e5;
}

label {
  display: inline-block;
  max-width: 100%;
  margin-bottom: 5px;
  font-weight: bold;
}

input[type="search"] {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

input[type="radio"],
input[type="checkbox"] {
  margin: 4px 0 0;
  margin-top: 1px \9;
  line-height: normal;
}

input[type="file"] {
  display: block;
}

input[type="range"] {
  display: block;
  width: 100%;
}

select[multiple],
select[size] {
  height: auto;
}

input[type="file"]:focus,
input[type="radio"]:focus,
input[type="checkbox"]:focus {
  outline: thin dotted;
  outline: 5px auto -webkit-focus-ring-color;
  outline-offset: -2px;
}

output {
  display: block;
  padding-top: 7px;
  font-size: 14px;
  line-height: 1.428571429;
  color: #555555;
}

.form-control {
  display: block;
  width: 100%;
  height: 34px;
  padding: 6px 12px;
  font-size: 14px;
  line-height: 1.428571429;
  color: #555555;
  background-color: #fff;
  background-image: none;
  border: 1px solid #ccc;
  border-radius: 4px;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
  -webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
  -o-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
  transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
}
.form-control:focus {
  border-color: #66afe9;
  outline: 0;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
}
.form-control::-moz-placeholder {
  color: #777777;
  opacity: 1;
}
.form-control:-ms-input-placeholder {
  color: #777777;
}
.form-control::-webkit-input-placeholder {
  color: #777777;
}
.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control {
  cursor: not-allowed;
  background-color: #eeeeee;
  opacity: 1;
}

textarea.form-control {
  height: auto;
}

input[type="search"] {
  -webkit-appearance: none;
}

input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"] {
  line-height: 34px;
  line-height: 1.428571429 \0;
}
input[type="date"].input-sm, .form-horizontal .form-group-sm input[type="date"].form-control, .input-group-sm > input[type="date"].form-control,
.input-group-sm > input[type="date"].input-group-addon,
.input-group-sm > .input-group-btn > input[type="date"].btn,
input[type="time"].input-sm,
.form-horizontal .form-group-sm input[type="time"].form-control,
.input-group-sm > input[type="time"].form-control,
.input-group-sm > input[type="time"].input-group-addon,
.input-group-sm > .input-group-btn > input[type="time"].btn,
input[type="datetime-local"].input-sm,
.form-horizontal .form-group-sm input[type="datetime-local"].form-control,
.input-group-sm > input[type="datetime-local"].form-control,
.input-group-sm > input[type="datetime-local"].input-group-addon,
.input-group-sm > .input-group-btn > input[type="datetime-local"].btn,
input[type="month"].input-sm,
.form-horizontal .form-group-sm input[type="month"].form-control,
.input-group-sm > input[type="month"].form-control,
.input-group-sm > input[type="month"].input-group-addon,
.input-group-sm > .input-group-btn > input[type="month"].btn {
  line-height: 30px;
}
input[type="date"].input-lg, .form-horizontal .form-group-lg input[type="date"].form-control, .input-group-lg > input[type="date"].form-control,
.input-group-lg > input[type="date"].input-group-addon,
.input-group-lg > .input-group-btn > input[type="date"].btn,
input[type="time"].input-lg,
.form-horizontal .form-group-lg input[type="time"].form-control,
.input-group-lg > input[type="time"].form-control,
.input-group-lg > input[type="time"].input-group-addon,
.input-group-lg > .input-group-btn > input[type="time"].btn,
input[type="datetime-local"].input-lg,
.form-horizontal .form-group-lg input[type="datetime-local"].form-control,
.input-group-lg > input[type="datetime-local"].form-control,
.input-group-lg > input[type="datetime-local"].input-group-addon,
.input-group-lg > .input-group-btn > input[type="datetime-local"].btn,
input[type="month"].input-lg,
.form-horizontal .form-group-lg input[type="month"].form-control,
.input-group-lg > input[type="month"].form-control,
.input-group-lg > input[type="month"].input-group-addon,
.input-group-lg > .input-group-btn > input[type="month"].btn {
  line-height: 46px;
}

.form-group {
  margin-bottom: 15px;
}

.radio,
.checkbox {
  position: relative;
  display: block;
  min-height: 20px;
  margin-top: 10px;
  margin-bottom: 10px;
}
.radio label,
.checkbox label {
  padding-left: 20px;
  margin-bottom: 0;
  font-weight: normal;
  cursor: pointer;
}

.radio input[type="radio"],
.radio-inline input[type="radio"],
.checkbox input[type="checkbox"],
.checkbox-inline input[type="checkbox"] {
  position: absolute;
  margin-left: -20px;
  margin-top: 4px \9;
}

.radio + .radio,
.checkbox + .checkbox {
  margin-top: -5px;
}

.radio-inline,
.checkbox-inline {
  display: inline-block;
  padding-left: 20px;
  margin-bottom: 0;
  vertical-align: middle;
  font-weight: normal;
  cursor: pointer;
}

.radio-inline + .radio-inline,
.checkbox-inline + .checkbox-inline {
  margin-top: 0;
  margin-left: 10px;
}

input[type="radio"][disabled], input[type="radio"].disabled, fieldset[disabled] input[type="radio"],
input[type="checkbox"][disabled],
input[type="checkbox"].disabled, fieldset[disabled]
input[type="checkbox"] {
  cursor: not-allowed;
}

.radio-inline.disabled, fieldset[disabled] .radio-inline,
.checkbox-inline.disabled, fieldset[disabled]
.checkbox-inline {
  cursor: not-allowed;
}

.radio.disabled label, fieldset[disabled] .radio label,
.checkbox.disabled label, fieldset[disabled]
.checkbox label {
  cursor: not-allowed;
}

.form-control-static {
  padding-top: 7px;
  padding-bottom: 7px;
  margin-bottom: 0;
}
.form-control-static.input-lg, .form-horizontal .form-group-lg .form-control-static.form-control, .input-group-lg > .form-control-static.form-control,
.input-group-lg > .form-control-static.input-group-addon,
.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,
.input-group-sm > .form-control-static.input-group-addon,
.input-group-sm > .input-group-btn > .form-control-static.btn {
  padding-left: 0;
  padding-right: 0;
}

.input-sm, .form-horizontal .form-group-sm .form-control, .input-group-sm > .form-control,
.input-group-sm > .input-group-addon,
.input-group-sm > .input-group-btn > .btn {
  height: 30px;
  padding: 5px 10px;
  font-size: 12px;
  line-height: 1.5;
  border-radius: 3px;
}

select.input-sm, .form-horizontal .form-group-sm select.form-control, .input-group-sm > select.form-control,
.input-group-sm > select.input-group-addon,
.input-group-sm > .input-group-btn > select.btn {
  height: 30px;
  line-height: 30px;
}

textarea.input-sm, .form-horizontal .form-group-sm textarea.form-control, .input-group-sm > textarea.form-control,
.input-group-sm > textarea.input-group-addon,
.input-group-sm > .input-group-btn > textarea.btn,
select[multiple].input-sm,
.form-horizontal .form-group-sm select[multiple].form-control,
.input-group-sm > select[multiple].form-control,
.input-group-sm > select[multiple].input-group-addon,
.input-group-sm > .input-group-btn > select[multiple].btn {
  height: auto;
}

.input-lg, .form-horizontal .form-group-lg .form-control, .input-group-lg > .form-control,
.input-group-lg > .input-group-addon,
.input-group-lg > .input-group-btn > .btn {
  height: 46px;
  padding: 10px 16px;
  font-size: 18px;
  line-height: 1.33;
  border-radius: 6px;
}

select.input-lg, .form-horizontal .form-group-lg select.form-control, .input-group-lg > select.form-control,
.input-group-lg > select.input-group-addon,
.input-group-lg > .input-group-btn > select.btn {
  height: 46px;
  line-height: 46px;
}

textarea.input-lg, .form-horizontal .form-group-lg textarea.form-control, .input-group-lg > textarea.form-control,
.input-group-lg > textarea.input-group-addon,
.input-group-lg > .input-group-btn > textarea.btn,
select[multiple].input-lg,
.form-horizontal .form-group-lg select[multiple].form-control,
.input-group-lg > select[multiple].form-control,
.input-group-lg > select[multiple].input-group-addon,
.input-group-lg > .input-group-btn > select[multiple].btn {
  height: auto;
}

.has-feedback {
  position: relative;
}
.has-feedback .form-control {
  padding-right: 42.5px;
}

.form-control-feedback {
  position: absolute;
  top: 25px;
  right: 0;
  z-index: 2;
  display: block;
  width: 34px;
  height: 34px;
  line-height: 34px;
  text-align: center;
}

.input-lg + .form-control-feedback, .form-horizontal .form-group-lg .form-control + .form-control-feedback, .input-group-lg > .form-control + .form-control-feedback,
.input-group-lg > .input-group-addon + .form-control-feedback,
.input-group-lg > .input-group-btn > .btn + .form-control-feedback {
  width: 46px;
  height: 46px;
  line-height: 46px;
}

.input-sm + .form-control-feedback, .form-horizontal .form-group-sm .form-control + .form-control-feedback, .input-group-sm > .form-control + .form-control-feedback,
.input-group-sm > .input-group-addon + .form-control-feedback,
.input-group-sm > .input-group-btn > .btn + .form-control-feedback {
  width: 30px;
  height: 30px;
  line-height: 30px;
}

.has-success .help-block,
.has-success .control-label,
.has-success .radio,
.has-success .checkbox,
.has-success .radio-inline,
.has-success .checkbox-inline {
  color: #3c763d;
}
.has-success .form-control {
  border-color: #3c763d;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}
.has-success .form-control:focus {
  border-color: #2b542c;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
}
.has-success .input-group-addon {
  color: #3c763d;
  border-color: #3c763d;
  background-color: #dff0d8;
}
.has-success .form-control-feedback {
  color: #3c763d;
}

.has-warning .help-block,
.has-warning .control-label,
.has-warning .radio,
.has-warning .checkbox,
.has-warning .radio-inline,
.has-warning .checkbox-inline {
  color: #8a6d3b;
}
.has-warning .form-control {
  border-color: #8a6d3b;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}
.has-warning .form-control:focus {
  border-color: #66512c;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;
}
.has-warning .input-group-addon {
  color: #8a6d3b;
  border-color: #8a6d3b;
  background-color: #fcf8e3;
}
.has-warning .form-control-feedback {
  color: #8a6d3b;
}

.has-error .help-block,
.has-error .control-label,
.has-error .radio,
.has-error .checkbox,
.has-error .radio-inline,
.has-error .checkbox-inline {
  color: #a94442;
}
.has-error .form-control {
  border-color: #a94442;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}
.has-error .form-control:focus {
  border-color: #843534;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
}
.has-error .input-group-addon {
  color: #a94442;
  border-color: #a94442;
  background-color: #f2dede;
}
.has-error .form-control-feedback {
  color: #a94442;
}

.has-feedback label.sr-only ~ .form-control-feedback {
  top: 0;
}

.help-block {
  display: block;
  margin-top: 5px;
  margin-bottom: 10px;
  color: #737373;
}

@media (min-width: 768px) {
  .form-inline .form-group, .navbar-form .form-group {
    display: inline-block;
    margin-bottom: 0;
    vertical-align: middle;
  }
  .form-inline .form-control, .navbar-form .form-control {
    display: inline-block;
    width: auto;
    vertical-align: middle;
  }
  .form-inline .input-group, .navbar-form .input-group {
    display: inline-table;
    vertical-align: middle;
  }
  .form-inline .input-group .input-group-addon, .navbar-form .input-group .input-group-addon,
  .form-inline .input-group .input-group-btn,
  .navbar-form .input-group .input-group-btn,
  .form-inline .input-group .form-control,
  .navbar-form .input-group .form-control {
    width: auto;
  }
  .form-inline .input-group > .form-control, .navbar-form .input-group > .form-control {
    width: 100%;
  }
  .form-inline .control-label, .navbar-form .control-label {
    margin-bottom: 0;
    vertical-align: middle;
  }
  .form-inline .radio, .navbar-form .radio,
  .form-inline .checkbox,
  .navbar-form .checkbox {
    display: inline-block;
    margin-top: 0;
    margin-bottom: 0;
    vertical-align: middle;
  }
  .form-inline .radio label, .navbar-form .radio label,
  .form-inline .checkbox label,
  .navbar-form .checkbox label {
    padding-left: 0;
  }
  .form-inline .radio input[type="radio"], .navbar-form .radio input[type="radio"],
  .form-inline .checkbox input[type="checkbox"],
  .navbar-form .checkbox input[type="checkbox"] {
    position: relative;
    margin-left: 0;
  }
  .form-inline .has-feedback .form-control-feedback, .navbar-form .has-feedback .form-control-feedback {
    top: 0;
  }
}

.form-horizontal .radio,
.form-horizontal .checkbox,
.form-horizontal .radio-inline,
.form-horizontal .checkbox-inline {
  margin-top: 0;
  margin-bottom: 0;
  padding-top: 7px;
}
.form-horizontal .radio,
.form-horizontal .checkbox {
  min-height: 27px;
}
.form-horizontal .form-group {
  margin-left: -15px;
  margin-right: -15px;
}
.form-horizontal .form-group:before, .form-horizontal .form-group:after {
  content: " ";
  display: table;
}
.form-horizontal .form-group:after {
  clear: both;
}
@media (min-width: 768px) {
  .form-horizontal .control-label {
    text-align: right;
    margin-bottom: 0;
    padding-top: 7px;
  }
}
.form-horizontal .has-feedback .form-control-feedback {
  top: 0;
  right: 15px;
}
@media (min-width: 768px) {
  .form-horizontal .form-group-lg .control-label {
    padding-top: 14.3px;
  }
}
@media (min-width: 768px) {
  .form-horizontal .form-group-sm .control-label {
    padding-top: 6px;
  }
}

.btn {
  display: inline-block;
  margin-bottom: 0;
  font-weight: normal;
  text-align: center;
  vertical-align: middle;
  cursor: pointer;
  background-image: none;
  border: 1px solid transparent;
  white-space: nowrap;
  padding: 6px 12px;
  font-size: 14px;
  line-height: 1.428571429;
  border-radius: 4px;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
.btn:focus, .btn:active:focus, .btn.active:focus {
  outline: thin dotted;
  outline: 5px auto -webkit-focus-ring-color;
  outline-offset: -2px;
}
.btn:hover, .btn:focus {
  color: #333;
  text-decoration: none;
}
.btn:active, .btn.active {
  outline: 0;
  background-image: none;
  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
}
.btn.disabled, .btn[disabled], fieldset[disabled] .btn {
  cursor: not-allowed;
  pointer-events: none;
  opacity: 0.65;
  filter: alpha(opacity=65);
  -webkit-box-shadow: none;
  box-shadow: none;
}

.btn-default {
  color: #333;
  background-color: #fff;
  border-color: #ccc;
}
.btn-default:hover, .btn-default:focus, .btn-default:active, .btn-default.active, .open > .btn-default.dropdown-toggle {
  color: #333;
  background-color: #e6e6e6;
  border-color: #adadad;
}
.btn-default:active, .btn-default.active, .open > .btn-default.dropdown-toggle {
  background-image: none;
}
.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 {
  background-color: #fff;
  border-color: #ccc;
}
.btn-default .badge {
  color: #fff;
  background-color: #333;
}

.btn-primary {
  color: #fff;
  background-color: #428bca;
  border-color: #357ebd;
}
.btn-primary:hover, .btn-primary:focus, .btn-primary:active, .btn-primary.active, .open > .btn-primary.dropdown-toggle {
  color: #fff;
  background-color: #3071a9;
  border-color: #285e8e;
}
.btn-primary:active, .btn-primary.active, .open > .btn-primary.dropdown-toggle {
  background-image: none;
}
.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 {
  background-color: #428bca;
  border-color: #357ebd;
}
.btn-primary .badge {
  color: #428bca;
  background-color: #fff;
}

.btn-success {
  color: #fff;
  background-color: #5cb85c;
  border-color: #4cae4c;
}
.btn-success:hover, .btn-success:focus, .btn-success:active, .btn-success.active, .open > .btn-success.dropdown-toggle {
  color: #fff;
  background-color: #449d44;
  border-color: #398439;
}
.btn-success:active, .btn-success.active, .open > .btn-success.dropdown-toggle {
  background-image: none;
}
.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 {
  background-color: #5cb85c;
  border-color: #4cae4c;
}
.btn-success .badge {
  color: #5cb85c;
  background-color: #fff;
}

.btn-info {
  color: #fff;
  background-color: #5bc0de;
  border-color: #46b8da;
}
.btn-info:hover, .btn-info:focus, .btn-info:active, .btn-info.active, .open > .btn-info.dropdown-toggle {
  color: #fff;
  background-color: #31b0d5;
  border-color: #269abc;
}
.btn-info:active, .btn-info.active, .open > .btn-info.dropdown-toggle {
  background-image: none;
}
.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 {
  background-color: #5bc0de;
  border-color: #46b8da;
}
.btn-info .badge {
  color: #5bc0de;
  background-color: #fff;
}

.btn-warning {
  color: #fff;
  background-color: #f0ad4e;
  border-color: #eea236;
}
.btn-warning:hover, .btn-warning:focus, .btn-warning:active, .btn-warning.active, .open > .btn-warning.dropdown-toggle {
  color: #fff;
  background-color: #ec971f;
  border-color: #d58512;
}
.btn-warning:active, .btn-warning.active, .open > .btn-warning.dropdown-toggle {
  background-image: none;
}
.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 {
  background-color: #f0ad4e;
  border-color: #eea236;
}
.btn-warning .badge {
  color: #f0ad4e;
  background-color: #fff;
}

.btn-danger {
  color: #fff;
  background-color: #d9534f;
  border-color: #d43f3a;
}
.btn-danger:hover, .btn-danger:focus, .btn-danger:active, .btn-danger.active, .open > .btn-danger.dropdown-toggle {
  color: #fff;
  background-color: #c9302c;
  border-color: #ac2925;
}
.btn-danger:active, .btn-danger.active, .open > .btn-danger.dropdown-toggle {
  background-image: none;
}
.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 {
  background-color: #d9534f;
  border-color: #d43f3a;
}
.btn-danger .badge {
  color: #d9534f;
  background-color: #fff;
}

.btn-link {
  color: #428bca;
  font-weight: normal;
  cursor: pointer;
  border-radius: 0;
}
.btn-link, .btn-link:active, .btn-link[disabled], fieldset[disabled] .btn-link {
  background-color: transparent;
  -webkit-box-shadow: none;
  box-shadow: none;
}
.btn-link, .btn-link:hover, .btn-link:focus, .btn-link:active {
  border-color: transparent;
}
.btn-link:hover, .btn-link:focus {
  color: #2a6496;
  text-decoration: underline;
  background-color: transparent;
}
.btn-link[disabled]:hover, .btn-link[disabled]:focus, fieldset[disabled] .btn-link:hover, fieldset[disabled] .btn-link:focus {
  color: #777777;
  text-decoration: none;
}

.btn-lg, .btn-group-lg > .btn {
  padding: 10px 16px;
  font-size: 18px;
  line-height: 1.33;
  border-radius: 6px;
}

.btn-sm, .btn-group-sm > .btn {
  padding: 5px 10px;
  font-size: 12px;
  line-height: 1.5;
  border-radius: 3px;
}

.btn-xs, .btn-group-xs > .btn {
  padding: 1px 5px;
  font-size: 12px;
  line-height: 1.5;
  border-radius: 3px;
}

.btn-block {
  display: block;
  width: 100%;
}

.btn-block + .btn-block {
  margin-top: 5px;
}

input[type="submit"].btn-block,
input[type="reset"].btn-block,
input[type="button"].btn-block {
  width: 100%;
}

.fade {
  opacity: 0;
  -webkit-transition: opacity 0.15s linear;
  -o-transition: opacity 0.15s linear;
  transition: opacity 0.15s linear;
}
.fade.in {
  opacity: 1;
}

.collapse {
  display: none;
}
.collapse.in {
  display: block;
}

tr.collapse.in {
  display: table-row;
}

tbody.collapse.in {
  display: table-row-group;
}

.collapsing {
  position: relative;
  height: 0;
  overflow: hidden;
  -webkit-transition: height 0.35s ease;
  -o-transition: height 0.35s ease;
  transition: height 0.35s ease;
}

.caret {
  display: inline-block;
  width: 0;
  height: 0;
  margin-left: 2px;
  vertical-align: middle;
  border-top: 4px solid;
  border-right: 4px solid transparent;
  border-left: 4px solid transparent;
}

.dropdown {
  position: relative;
}

.dropdown-toggle:focus {
  outline: 0;
}

.dropdown-menu {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 1000;
  display: none;
  float: left;
  min-width: 160px;
  padding: 5px 0;
  margin: 2px 0 0;
  list-style: none;
  font-size: 14px;
  text-align: left;
  background-color: #fff;
  border: 1px solid #ccc;
  border: 1px solid rgba(0, 0, 0, 0.15);
  border-radius: 4px;
  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
  background-clip: padding-box;
}
.dropdown-menu.pull-right {
  right: 0;
  left: auto;
}
.dropdown-menu .divider {
  height: 1px;
  margin: 9px 0;
  overflow: hidden;
  background-color: #e5e5e5;
}
.dropdown-menu > li > a {
  display: block;
  padding: 3px 20px;
  clear: both;
  font-weight: normal;
  line-height: 1.428571429;
  color: #333333;
  white-space: nowrap;
}

.dropdown-menu > li > a:hover, .dropdown-menu > li > a:focus {
  text-decoration: none;
  color: #262626;
  background-color: #f5f5f5;
}

.dropdown-menu > .active > a, .dropdown-menu > .active > a:hover, .dropdown-menu > .active > a:focus {
  color: #fff;
  text-decoration: none;
  outline: 0;
  background-color: #428bca;
}

.dropdown-menu > .disabled > a, .dropdown-menu > .disabled > a:hover, .dropdown-menu > .disabled > a:focus {
  color: #777777;
}

.dropdown-menu > .disabled > a:hover, .dropdown-menu > .disabled > a:focus {
  text-decoration: none;
  background-color: transparent;
  background-image: none;
  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
  cursor: not-allowed;
}

.open > .dropdown-menu {
  display: block;
}
.open > a {
  outline: 0;
}

.dropdown-menu-right {
  left: auto;
  right: 0;
}

.dropdown-menu-left {
  left: 0;
  right: auto;
}

.dropdown-header {
  display: block;
  padding: 3px 20px;
  font-size: 12px;
  line-height: 1.428571429;
  color: #777777;
  white-space: nowrap;
}

.dropdown-backdrop {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  top: 0;
  z-index: 990;
}

.pull-right > .dropdown-menu {
  right: 0;
  left: auto;
}

.dropup .caret,
.navbar-fixed-bottom .dropdown .caret {
  border-top: 0;
  border-bottom: 4px solid;
  content: "";
}
.dropup .dropdown-menu,
.navbar-fixed-bottom .dropdown .dropdown-menu {
  top: auto;
  bottom: 100%;
  margin-bottom: 1px;
}

@media (min-width: 768px) {
  .navbar-right .dropdown-menu {
    right: 0;
    left: auto;
  }
  .navbar-right .dropdown-menu-left {
    left: 0;
    right: auto;
  }
}
.btn-group,
.btn-group-vertical {
  position: relative;
  display: inline-block;
  vertical-align: middle;
}
.btn-group > .btn,
.btn-group-vertical > .btn {
  position: relative;
  float: left;
}
.btn-group > .btn:hover, .btn-group > .btn:focus, .btn-group > .btn:active, .btn-group > .btn.active,
.btn-group-vertical > .btn:hover,
.btn-group-vertical > .btn:focus,
.btn-group-vertical > .btn:active,
.btn-group-vertical > .btn.active {
  z-index: 2;
}
.btn-group > .btn:focus,
.btn-group-vertical > .btn:focus {
  outline: 0;
}

.btn-group .btn + .btn,
.btn-group .btn + .btn-group,
.btn-group .btn-group + .btn,
.btn-group .btn-group + .btn-group {
  margin-left: -1px;
}

.btn-toolbar {
  margin-left: -5px;
}
.btn-toolbar:before, .btn-toolbar:after {
  content: " ";
  display: table;
}
.btn-toolbar:after {
  clear: both;
}
.btn-toolbar .btn-group,
.btn-toolbar .input-group {
  float: left;
}
.btn-toolbar > .btn,
.btn-toolbar > .btn-group,
.btn-toolbar > .input-group {
  margin-left: 5px;
}

.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
  border-radius: 0;
}

.btn-group > .btn:first-child {
  margin-left: 0;
}
.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {
  border-bottom-right-radius: 0;
  border-top-right-radius: 0;
}

.btn-group > .btn:last-child:not(:first-child),
.btn-group > .dropdown-toggle:not(:first-child) {
  border-bottom-left-radius: 0;
  border-top-left-radius: 0;
}

.btn-group > .btn-group {
  float: left;
}

.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
  border-radius: 0;
}

.btn-group > .btn-group:first-child > .btn:last-child,
.btn-group > .btn-group:first-child > .dropdown-toggle {
  border-bottom-right-radius: 0;
  border-top-right-radius: 0;
}

.btn-group > .btn-group:last-child > .btn:first-child {
  border-bottom-left-radius: 0;
  border-top-left-radius: 0;
}

.btn-group .dropdown-toggle:active,
.btn-group.open .dropdown-toggle {
  outline: 0;
}

.btn-group > .btn + .dropdown-toggle {
  padding-left: 8px;
  padding-right: 8px;
}

.btn-group > .btn-lg + .dropdown-toggle, .btn-group-lg.btn-group > .btn + .dropdown-toggle {
  padding-left: 12px;
  padding-right: 12px;
}

.btn-group.open .dropdown-toggle {
  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.1
Download .txt
gitextract_p3cg83uv/

├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       └── release.yml
├── .gitignore
├── .ruby-version
├── .travis.yml
├── AUTHORS.md
├── CONTRIBUTING.md
├── Dockerfile
├── Gemfile
├── Jarfile
├── LICENSE.md
├── NOTICE.txt
├── README.md
├── Rakefile
├── build/
│   ├── appbundler-1.0.jar
│   ├── dist-LICENSE.txt
│   ├── dist-README.txt
│   └── icons/
│       └── tabula.icns
├── build.xml
├── config.rb
├── config.ru
├── docker-compose.yml
├── lib/
│   ├── tabula_java_wrapper.rb
│   ├── tabula_job_executor/
│   │   ├── executor.rb
│   │   └── jobs/
│   │       ├── detect_tables.rb
│   │       ├── generate_document_data.rb
│   │       └── generate_thumbnails.rb
│   ├── tabula_workspace.rb
│   └── thumbnail_generator.rb
└── webapp/
    ├── index.html
    ├── static/
    │   ├── css/
    │   │   ├── _bootstrap-variables.scss
    │   │   ├── selectors.css
    │   │   └── styles.css
    │   ├── js/
    │   │   ├── debug_pdf_view.js
    │   │   ├── library.js
    │   │   ├── pdf_view.js
    │   │   ├── rectangularSelector.js
    │   │   ├── resizableSelection.js
    │   │   ├── tabula.js
    │   │   ├── template_library.js
    │   │   └── vendor/
    │   │       ├── backbone-min.js
    │   │       ├── bootstrap/
    │   │       │   ├── affix.js
    │   │       │   ├── alert.js
    │   │       │   ├── button.js
    │   │       │   ├── carousel.js
    │   │       │   ├── collapse.js
    │   │       │   ├── dropdown.js
    │   │       │   ├── modal.js
    │   │       │   ├── popover.js
    │   │       │   ├── scrollspy.js
    │   │       │   ├── tab.js
    │   │       │   ├── tooltip.js
    │   │       │   └── transition.js
    │   │       ├── bootstrap.js
    │   │       ├── handlebars-v1.3.0.js
    │   │       ├── table2CSV.js
    │   │       ├── underscore-min.js
    │   │       └── upload-group.js
    │   ├── sass/
    │   │   ├── _bootstrap-variables.scss
    │   │   ├── selectors.scss
    │   │   └── styles.scss
    │   └── swf/
    │       └── ZeroClipboard.swf
    ├── tabula_debug.rb
    ├── tabula_job_progress.rb
    ├── tabula_settings.rb
    └── tabula_web.rb
Download .txt
SYMBOL INDEX (164 symbols across 27 files)

FILE: lib/tabula_java_wrapper.rb
  class Java::TechnologyTabula::Table (line 4) | class Java::TechnologyTabula::Table
    method to_csv (line 6) | def to_csv
    method to_tsv (line 12) | def to_tsv
    method to_json (line 18) | def to_json(*a)
  type Tabula (line 25) | module Tabula
    function extract_tables (line 27) | def Tabula.extract_tables(pdf_path, specs, options={})
    type Extraction (line 66) | module Extraction
      function openPDF (line 68) | def Extraction.openPDF(pdf_filename, password='')
      class ObjectExtractor (line 73) | class ObjectExtractor < Java::TechnologyTabula.ObjectExtractor
        method initialize (line 79) | def initialize(pdf_filename, pages=[1], password='', options={})
        method page_count (line 87) | def page_count
      class PagesInfoExtractor (line 93) | class PagesInfoExtractor < ObjectExtractor
        method pages (line 95) | def pages

FILE: lib/tabula_job_executor/executor.rb
  type Tabula (line 11) | module Tabula
    class NoTextDataException (line 12) | class NoTextDataException < IOError; end
    type Background (line 14) | module Background
      class JobExecutor (line 16) | class JobExecutor < java.util.concurrent.ThreadPoolExecutor
        method initialize (line 21) | def initialize
        method afterExecute (line 37) | def afterExecute(runnable, throwable)
        method submit (line 63) | def submit(job)
        method get (line 70) | def get(uuid)
        method get_by_batch (line 74) | def get_by_batch(uuid)
      class Job (line 82) | class Job
        method initialize (line 88) | def initialize(options={})
        method [] (line 94) | def [](k)
        method name (line 98) | def name
        method call (line 102) | def call
        method [] (line 108) | def [](k)
        method at (line 112) | def at(num, total, *messages)
        method queued (line 116) | def queued
        method warn (line 120) | def warn(*warnings)
        method failed (line 124) | def failed(*messages)
        method completed (line 128) | def completed
        method pct_complete (line 132) | def pct_complete
        method message (line 142) | def message
        method warning (line 148) | def warning
        method create (line 162) | def create(options)
  class K (line 176) | class K < Tabula::Background::Job
    method perform (line 177) | def perform
  class J (line 187) | class J < Tabula::Background::Job
    method perform (line 188) | def perform

FILE: lib/tabula_job_executor/jobs/detect_tables.rb
  class DetectTablesJob (line 5) | class DetectTablesJob < Tabula::Background::Job
    method perform (line 7) | def perform

FILE: lib/tabula_job_executor/jobs/generate_document_data.rb
  class GenerateDocumentDataJob (line 6) | class GenerateDocumentDataJob < Tabula::Background::Job
    method perform (line 10) | def perform

FILE: lib/tabula_job_executor/jobs/generate_thumbnails.rb
  class GenerateThumbnailJob (line 4) | class GenerateThumbnailJob < Tabula::Background::Job
    method perform (line 7) | def perform

FILE: lib/tabula_workspace.rb
  type Tabula (line 4) | module Tabula
    class Workspace (line 5) | class Workspace
      method initialize (line 12) | def initialize(data_dir=TabulaSettings.getDataDir)
      method add_document (line 25) | def add_document(document, pages)
      method delete_document (line 32) | def delete_document(document_id)
      method delete_page (line 40) | def delete_page(document_id, page_number)
      method get_document_metadata (line 45) | def get_document_metadata(document_id)
      method get_document_pages (line 50) | def get_document_pages(document_id)
      method get_document_path (line 54) | def get_document_path(document_id)
      method list_documents (line 58) | def list_documents
      method get_data_dir (line 65) | def get_data_dir()
      method add_file (line 69) | def add_file(contents, document_id, filename)
      method move_file (line 77) | def move_file(path, document_id, filename)
      method copy_file (line 81) | def copy_file(path, document_id, filename)
      method list_templates (line 85) | def list_templates
      method get_template_metadata (line 90) | def get_template_metadata(template_id)
      method get_template_body (line 94) | def get_template_body(template_id)
      method add_template (line 99) | def add_template(template_metadata)
      method replace_template_metadata (line 115) | def replace_template_metadata(template_id, template_metadata)
      method delete_template (line 124) | def delete_template(template_id)
      method write_template_file (line 134) | def write_template_file(template_metadata)
      method get_templates_dir (line 141) | def get_templates_dir
      method get_document_dir (line 148) | def get_document_dir(document_id)
      method read_workspace! (line 157) | def read_workspace!
      method flush_workspace! (line 171) | def flush_workspace!

FILE: lib/thumbnail_generator.rb
  class AbstractThumbnailGenerator (line 13) | class AbstractThumbnailGenerator
    method initialize (line 16) | def initialize(pdf_filename, output_directory, sizes=[2048, 560])
    method generate_thumbnails! (line 24) | def generate_thumbnails!
  class PDFBoxThumbnailGenerator (line 29) | class PDFBoxThumbnailGenerator < AbstractThumbnailGenerator
    method initialize (line 30) | def initialize(pdf_filename, output_directory, document_id, sizes=[204...
    method generate_thumbnails! (line 37) | def generate_thumbnails!
  class MUDrawThumbnailGenerator (line 67) | class MUDrawThumbnailGenerator < AbstractThumbnailGenerator
    method initialize (line 69) | def initialize(pdf_filename, output_directory, sizes=[2048, 560], mudr...
    method generate_thumbnails! (line 74) | def generate_thumbnails!

FILE: webapp/static/js/pdf_view.js
  function isElementPartiallyInViewport (line 1462) | function isElementPartiallyInViewport (el) {
  function isElementPartiallyInContainer (line 1477) | function isElementPartiallyInContainer (el, container) {
  function isElementInViewport (line 1502) | function isElementInViewport (el) {
  function roundTo (line 1517) | function roundTo(num, fancymathwordforthenumberofdigitsafterthedecimal){

FILE: webapp/static/js/vendor/bootstrap.js
  function Plugin (line 119) | function Plugin(option) {
  function removeElement (line 211) | function removeElement() {
  function Plugin (line 227) | function Plugin(option) {
  function Plugin (line 332) | function Plugin(option) {
  function Plugin (line 554) | function Plugin(option) {
  function getTargetFromTrigger (line 773) | function getTargetFromTrigger($trigger) {
  function Plugin (line 785) | function Plugin(option) {
  function clearMenus (line 917) | function clearMenus(e) {
  function getParent (line 936) | function getParent($this) {
  function Plugin (line 953) | function Plugin(option) {
  function next (line 1060) | function next() {
  function Plugin (line 1106) | function Plugin(option) {
  function transitionEnd (line 1160) | function transitionEnd() {
  function ScrollSpy (line 1220) | function ScrollSpy(element, options) {
  function Plugin (line 1343) | function Plugin(option) {
  function Plugin (line 1657) | function Plugin(option, _relatedTarget) {
  function complete (line 1999) | function complete() {
  function Plugin (line 2151) | function Plugin(option) {
  function Plugin (line 2271) | function Plugin(option) {

FILE: webapp/static/js/vendor/bootstrap/affix.js
  function Plugin (line 119) | function Plugin(option) {

FILE: webapp/static/js/vendor/bootstrap/alert.js
  function removeElement (line 48) | function removeElement() {
  function Plugin (line 64) | function Plugin(option) {

FILE: webapp/static/js/vendor/bootstrap/button.js
  function Plugin (line 74) | function Plugin(option) {

FILE: webapp/static/js/vendor/bootstrap/carousel.js
  function Plugin (line 179) | function Plugin(option) {

FILE: webapp/static/js/vendor/bootstrap/collapse.js
  function getTargetFromTrigger (line 157) | function getTargetFromTrigger($trigger) {
  function Plugin (line 169) | function Plugin(option) {

FILE: webapp/static/js/vendor/bootstrap/dropdown.js
  function clearMenus (line 89) | function clearMenus(e) {
  function getParent (line 108) | function getParent($this) {
  function Plugin (line 125) | function Plugin(option) {

FILE: webapp/static/js/vendor/bootstrap/modal.js
  function Plugin (line 277) | function Plugin(option, _relatedTarget) {

FILE: webapp/static/js/vendor/bootstrap/popover.js
  function Plugin (line 87) | function Plugin(option) {

FILE: webapp/static/js/vendor/bootstrap/scrollspy.js
  function ScrollSpy (line 16) | function ScrollSpy(element, options) {
  function Plugin (line 139) | function Plugin(option) {

FILE: webapp/static/js/vendor/bootstrap/tab.js
  function next (line 70) | function next() {
  function Plugin (line 116) | function Plugin(option) {

FILE: webapp/static/js/vendor/bootstrap/tooltip.js
  function complete (line 294) | function complete() {
  function Plugin (line 446) | function Plugin(option) {

FILE: webapp/static/js/vendor/bootstrap/transition.js
  function transitionEnd (line 16) | function transitionEnd() {

FILE: webapp/static/js/vendor/handlebars-v1.3.0.js
  function SafeString (line 34) | function SafeString(string) {
  function escapeChar (line 65) | function escapeChar(chr) {
  function extend (line 69) | function extend(obj, value) {
  function escapeExpression (line 97) | function escapeExpression(string) {
  function isEmpty (line 114) | function isEmpty(value) {
  function Exception (line 135) | function Exception(message, node) {
  function HandlebarsEnvironment (line 184) | function HandlebarsEnvironment(helpers, partials) {
  function registerDefaultHelpers (line 216) | function registerDefaultHelpers(instance) {
  function log (line 337) | function log(level, obj) { logger.log(level, obj); }
  function checkRevision (line 357) | function checkRevision(compilerInfo) {
  function template (line 377) | function template(templateSpec, env) {
  function programWithDepth (line 451) | function programWithDepth(i, fn, data /*, $depth */) {
  function program (line 464) | function program(i, fn, data) {
  function invokePartial (line 475) | function invokePartial(partial, name, context, helpers, partials, data) {
  function noop (line 485) | function noop() { return ""; }
  function LocationInfo (line 535) | function LocationInfo(locInfo){
  function popStack (line 886) | function popStack(n) {
  function lex (line 891) | function lex() {
  function stripFlags (line 979) | function stripFlags(open, close) {
  function strip (line 1158) | function strip(start, end) {
  function Parser (line 1251) | function Parser () { this.yy = {}; }
  function parse (line 1267) | function parse(input) {
  function Compiler (line 1285) | function Compiler() {}
  function precompile (line 1706) | function precompile(input, options, env) {
  function compile (line 1721) | function compile(input, options, env) {
  function Literal (line 1763) | function Literal(value) {
  function JavaScriptCompiler (line 1767) | function JavaScriptCompiler() {}

FILE: webapp/static/js/vendor/table2CSV.js
  function row2CSV (line 45) | function row2CSV(tmpRow) {
  function formatData (line 53) | function formatData(input) {
  function popup (line 63) | function popup(data) {

FILE: webapp/tabula_debug.rb
  class TabulaDebug (line 3) | class TabulaDebug < Cuba

FILE: webapp/tabula_job_progress.rb
  class TabulaJobProgress (line 8) | class TabulaJobProgress < Cuba

FILE: webapp/tabula_settings.rb
  type TabulaSettings (line 4) | module TabulaSettings
    function getDataDir (line 12) | def self.getDataDir
    function enableDebug (line 63) | def self.enableDebug
    function disableVersionCheck (line 79) | def self.disableVersionCheck
    function disableNotifications (line 88) | def self.disableNotifications

FILE: webapp/tabula_web.rb
  function is_valid_pdf? (line 32) | def is_valid_pdf?(path)
  function upload (line 51) | def upload(file)
  class InvalidTemplateError (line 85) | class InvalidTemplateError < StandardError; end
  function upload_template (line 87) | def upload_template(template_file)
Condensed preview — 66 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (761K chars).
[
  {
    "path": ".github/FUNDING.yml",
    "chars": 75,
    "preview": "# These are supported funding model platforms\n\nopen_collective: tabulapdf\n\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 515,
    "preview": "on:\n  release:\n    types: [published]\npermissions:\n  contents: read\n  packages: write\njobs:\n  release:\n    runs-on: ubun"
  },
  {
    "path": ".gitignore",
    "chars": 416,
    "preview": "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.ap"
  },
  {
    "path": ".ruby-version",
    "chars": 15,
    "preview": "jruby-9.2.13.0\n"
  },
  {
    "path": ".travis.yml",
    "chars": 303,
    "preview": "sudo: false\nlanguage: ruby\ndist: trusty\nbefore_install:\n  - gem update --system\n  - gem install bundler\n  - gem install "
  },
  {
    "path": "AUTHORS.md",
    "chars": 802,
    "preview": "# Authors & Acknowledgments\n\nTabula was originally started by Manuel Aristarán in late 2012.\n\nThe PRIMARY AUTHORS are (a"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 2667,
    "preview": "CONTRIBUTING\n============\n\nTabula is an open-source project, which means it depends on volunteers to build and improve i"
  },
  {
    "path": "Dockerfile",
    "chars": 721,
    "preview": "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"
  },
  {
    "path": "Gemfile",
    "chars": 498,
    "preview": "#since war/jar bundle requires gem package; use gem-in-a-box for testing\n#or execute tabula via \"rackup\".\n#source \"http:"
  },
  {
    "path": "Jarfile",
    "chars": 39,
    "preview": "jar 'technology.tabula:tabula', '1.0.4'"
  },
  {
    "path": "LICENSE.md",
    "chars": 1087,
    "preview": "Copyright (C) 2012-2020 Manuel Aristarán <jazzido@jazzido.com>\n\nPermission is hereby granted, free of charge, to any per"
  },
  {
    "path": "NOTICE.txt",
    "chars": 230,
    "preview": "Tabula\n© 2012-2020 Manuel Aristarán. Available under MIT License. See `AUTHORS.md`\nand `LICENSE.md`.\n\nThis product inclu"
  },
  {
    "path": "README.md",
    "chars": 18350,
    "preview": "**Is `tabula` an active project?**\n\nTabula is, and always has been, a volunteer-run project. We've occasionally had fund"
  },
  {
    "path": "Rakefile",
    "chars": 7387,
    "preview": "require 'fileutils'\nrequire 'warbler'\n\n########## java jar compilation ##########\n\nWarbler::Task.new(\"war\",\n  Warbler::C"
  },
  {
    "path": "build/dist-LICENSE.txt",
    "chars": 3175,
    "preview": "tabula and tabula-extractor\n\nCopyright (C) 2012-2020 Manuel Aristarán <jazzido@jazzido.com>\n\nPermission is hereby grante"
  },
  {
    "path": "build/dist-README.txt",
    "chars": 1774,
    "preview": "# Tabula\n\nTabula helps you liberate data tables trapped inside PDF files.\n\n* The latest downloads and documentation are "
  },
  {
    "path": "build.xml",
    "chars": 3967,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project name=\"tabula\" default=\"build\" basedir=\".\">\n\n  <property file=\"build.prop"
  },
  {
    "path": "config.rb",
    "chars": 964,
    "preview": "require 'compass/import-once/activate'\n# Require any additional compass plugins here.\nrequire 'bootstrap-sass'\n# Set thi"
  },
  {
    "path": "config.ru",
    "chars": 3483,
    "preview": "# encoding: UTF-8\nrequire 'rubygems'\nrequire 'bundler'\nBundler.require\n\n# Disable LittleCMS when running in JVM >= 1.8\n#"
  },
  {
    "path": "docker-compose.yml",
    "chars": 250,
    "preview": "version: '3.3'\nservices:\n  web: &web\n    build:\n      context: .\n    command: \"jruby -G -r jbundler -S rackup -p 9292 -o"
  },
  {
    "path": "lib/tabula_java_wrapper.rb",
    "chars": 3351,
    "preview": "java_import org.apache.pdfbox.pdmodel.PDDocument\njava_import org.apache.pdfbox.pdmodel.encryption.StandardDecryptionMate"
  },
  {
    "path": "lib/tabula_job_executor/executor.rb",
    "chars": 5390,
    "preview": "require 'java'\njava_import java.util.concurrent.ThreadPoolExecutor\njava_import java.util.concurrent.TimeUnit\njava_import"
  },
  {
    "path": "lib/tabula_job_executor/jobs/detect_tables.rb",
    "chars": 1155,
    "preview": "require 'java'\n\nrequire_relative '../executor.rb'\n\nclass DetectTablesJob < Tabula::Background::Job\n  include Observable\n"
  },
  {
    "path": "lib/tabula_job_executor/jobs/generate_document_data.rb",
    "chars": 1135,
    "preview": "require 'json'\nrequire 'jruby/synchronized'\n\nrequire_relative '../executor.rb'\n\nclass GenerateDocumentDataJob < Tabula::"
  },
  {
    "path": "lib/tabula_job_executor/jobs/generate_thumbnails.rb",
    "chars": 579,
    "preview": "require_relative '../executor.rb'\nrequire_relative '../../thumbnail_generator.rb'\n\nclass GenerateThumbnailJob < Tabula::"
  },
  {
    "path": "lib/tabula_workspace.rb",
    "chars": 5233,
    "preview": "require 'jruby/synchronized'\nrequire 'singleton'\n\nmodule Tabula\n  class Workspace\n    include JRuby::Synchronized\n    in"
  },
  {
    "path": "lib/thumbnail_generator.rb",
    "chars": 2554,
    "preview": "# coding: utf-8\nrequire 'java'\nrequire 'observer'\n\njava_import javax.imageio.ImageIO\njava_import java.awt.image.Buffered"
  },
  {
    "path": "webapp/index.html",
    "chars": 29489,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<!-- Tabula.api_version : ask for it on the console. -->\n  <head>\n    <meta charset=\"ut"
  },
  {
    "path": "webapp/static/css/_bootstrap-variables.scss",
    "chars": 28121,
    "preview": "// Override Bootstrap variables here (defaults from bootstrap-sass v3.3.1.0):\n\n// When true, asset path helpers are used"
  },
  {
    "path": "webapp/static/css/selectors.css",
    "chars": 2220,
    "preview": ".thumbnail-list li div.selection-show {\n  position: absolute;\n  border: 1px dashed red;\n  display: none;\n  pointer-event"
  },
  {
    "path": "webapp/static/css/styles.css",
    "chars": 166903,
    "preview": "@charset \"UTF-8\";\n/*!\n * WARNING: Don't edit this file by hand! Instead, you should be using Compass.\n * Edit the file i"
  },
  {
    "path": "webapp/static/js/debug_pdf_view.js",
    "chars": 5586,
    "preview": "Tabula.DebugPDFView = {\n    colors: ['#f00', '#0f0', '#00f', '#ffff00', '#FF00FF'],\n    debugRulings: function(image, re"
  },
  {
    "path": "webapp/static/js/library.js",
    "chars": 12786,
    "preview": "Tabula = window.Tabula || {};\nvar base_uri = $('base').attr(\"href\");\n\nTabula.FileUpload = Backbone.Model.extend({\n  // i"
  },
  {
    "path": "webapp/static/js/pdf_view.js",
    "chars": 63687,
    "preview": "Tabula = Tabula || {};\n\nvar clip = null;\nvar base_uri = $('base').attr(\"href\");\n\nPDF_ID = window.location.pathname.repla"
  },
  {
    "path": "webapp/static/js/rectangularSelector.js",
    "chars": 4185,
    "preview": "/* jshint undef: true, unused: true */\n/* global $, _, console, document */\n\n(function (name, context, definition) {\n  i"
  },
  {
    "path": "webapp/static/js/resizableSelection.js",
    "chars": 5152,
    "preview": "/* jshint undef: true, unused: true */\n/* global $, paper, Backbone, _, console */\n\n(function (name, context, definition"
  },
  {
    "path": "webapp/static/js/tabula.js",
    "chars": 8903,
    "preview": "var Tabula;\nwindow.Tabula = Tabula || {};\n$.ajaxSetup({ cache: false }); // fixes a dumb issue where Internet Explorer c"
  },
  {
    "path": "webapp/static/js/template_library.js",
    "chars": 5849,
    "preview": "Backbone.emulateJSON = true;\nTabula.SavedTemplate = Backbone.Model.extend({\n  // templates.push({\"name\": \"fake test temp"
  },
  {
    "path": "webapp/static/js/vendor/backbone-min.js",
    "chars": 19999,
    "preview": "(function(t,e){if(typeof define===\"function\"&&define.amd){define([\"underscore\",\"jquery\",\"exports\"],function(i,r,s){t.Bac"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/affix.js",
    "chars": 4791,
    "preview": "/* ========================================================================\n * Bootstrap: affix.js v3.3.1\n * http://getb"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/alert.js",
    "chars": 2260,
    "preview": "/* ========================================================================\n * Bootstrap: alert.js v3.3.1\n * http://getb"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/button.js",
    "chars": 3274,
    "preview": "/* ========================================================================\n * Bootstrap: button.js v3.3.1\n * http://get"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/carousel.js",
    "chars": 7098,
    "preview": "/* ========================================================================\n * Bootstrap: carousel.js v3.3.1\n * http://g"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/collapse.js",
    "chars": 5977,
    "preview": "/* ========================================================================\n * Bootstrap: collapse.js v3.3.1\n * http://g"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/dropdown.js",
    "chars": 4696,
    "preview": "/* ========================================================================\n * Bootstrap: dropdown.js v3.3.1\n * http://g"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/modal.js",
    "chars": 9343,
    "preview": "/* ========================================================================\n * Bootstrap: modal.js v3.3.1\n * http://getb"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/popover.js",
    "chars": 3507,
    "preview": "/* ========================================================================\n * Bootstrap: popover.js v3.3.1\n * http://ge"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/scrollspy.js",
    "chars": 4697,
    "preview": "/* ========================================================================\n * Bootstrap: scrollspy.js v3.3.1\n * http://"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/tab.js",
    "chars": 3789,
    "preview": "/* ========================================================================\n * Bootstrap: tab.js v3.3.1\n * http://getboo"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/tooltip.js",
    "chars": 15336,
    "preview": "/* ========================================================================\n * Bootstrap: tooltip.js v3.3.1\n * http://ge"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap/transition.js",
    "chars": 1831,
    "preview": "/* ========================================================================\n * Bootstrap: transition.js v3.3.1\n * http:/"
  },
  {
    "path": "webapp/static/js/vendor/bootstrap.js",
    "chars": 66611,
    "preview": "/* ========================================================================\n * Bootstrap: affix.js v3.3.1\n * http://getb"
  },
  {
    "path": "webapp/static/js/vendor/handlebars-v1.3.0.js",
    "chars": 89667,
    "preview": "/*!\n\n handlebars v1.3.0\n\nCopyright (C) 2011 by Yehuda Katz\n\nPermission is hereby granted, free of charge, to any person "
  },
  {
    "path": "webapp/static/js/vendor/table2CSV.js",
    "chars": 2332,
    "preview": "jQuery.fn.table2CSV = function(options) {\n    var options = jQuery.extend({\n        separator: ',',\n        header: [],\n"
  },
  {
    "path": "webapp/static/js/vendor/underscore-min.js",
    "chars": 13450,
    "preview": "(function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.conca"
  },
  {
    "path": "webapp/static/js/vendor/upload-group.js",
    "chars": 674,
    "preview": "$(document).on('change', '.btn-file :file', function() {\n  var input = $(this),\n      numFiles = input.get(0).files ? in"
  },
  {
    "path": "webapp/static/sass/_bootstrap-variables.scss",
    "chars": 28121,
    "preview": "// Override Bootstrap variables here (defaults from bootstrap-sass v3.3.1.0):\n\n// When true, asset path helpers are used"
  },
  {
    "path": "webapp/static/sass/selectors.scss",
    "chars": 3975,
    "preview": ".thumbnail-list li div.selection-show {\n    position: absolute;\n    border: 1px dashed red;\n    display: none;\n    point"
  },
  {
    "path": "webapp/static/sass/styles.scss",
    "chars": 9753,
    "preview": "// IGNORE THE WARNING BELOW. If you're in styles.scss, you're in the right place. :)\n/*!\n * WARNING: Don't edit this fil"
  },
  {
    "path": "webapp/tabula_debug.rb",
    "chars": 3676,
    "preview": "require 'json'\n\nclass TabulaDebug < Cuba\n  define do\n\n    on \":file_id/characters\" do |file_id|\n      par = JSON.load(re"
  },
  {
    "path": "webapp/tabula_job_progress.rb",
    "chars": 3859,
    "preview": "require_relative '../lib/tabula_job_executor/executor.rb'\n\n# if this is true, then the progress bar will complete (and g"
  },
  {
    "path": "webapp/tabula_settings.rb",
    "chars": 3051,
    "preview": "# encoding: UTF-8\nrequire 'fileutils'\n\nmodule TabulaSettings\n\n  ########## Defaults ##########\n  DEFAULT_DEBUG = false\n "
  },
  {
    "path": "webapp/tabula_web.rb",
    "chars": 17012,
    "preview": "# -*- coding: utf-8 -*-\nrequire 'cuba'\nrequire 'cuba/render'\n\nrequire 'digest/sha1'\nrequire 'json'\nrequire 'csv'\nrequire"
  }
]

// ... and 3 more files (download for full content)

About this extraction

This page contains the full source code of the tabulapdf/tabula GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 66 files (710.7 KB), approximately 197.8k tokens, and a symbol index with 164 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!