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)
[](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="💩SV">💩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">×</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">×</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… <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… <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
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
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.