master 9b0063c9731f cached
258 files
2.0 MB
550.1k tokens
638 symbols
1 requests
Download .txt
Showing preview only (2,195K chars total). Download the full file or copy to clipboard to get everything.
Repository: the-paperless-project/paperless
Branch: master
Commit: 9b0063c9731f
Files: 258
Total size: 2.0 MB

Directory structure:
gitextract_yqrokexp/

├── .docker-hub-test
├── .editorconfig
├── .gitattributes
├── .gitignore
├── .travis.yml
├── CODE_OF_CONDUCT.md
├── Dockerfile
├── LICENSE
├── Pipfile
├── README-de.md
├── README-el.md
├── README.md
├── THANKS.md
├── ci/
│   └── deploy-docker
├── data/
│   └── .keep
├── docker-compose.env.example
├── docker-compose.yml.example
├── docs/
│   ├── Dockerfile
│   ├── Makefile
│   ├── _static/
│   │   ├── .keep
│   │   └── custom.css
│   ├── api.rst
│   ├── changelog.rst
│   ├── conf.py
│   ├── consumption.rst
│   ├── contributing.rst
│   ├── customising.rst
│   ├── examples/
│   │   └── lxc/
│   │       ├── lxc-install.sh
│   │       └── paperless.conf
│   ├── extending.rst
│   ├── guesswork.rst
│   ├── index.rst
│   ├── migrating.rst
│   ├── requirements.rst
│   ├── requirements.txt
│   ├── scanners.rst
│   ├── screenshots.rst
│   ├── setup.rst
│   ├── troubleshooting.rst
│   └── utilities.rst
├── management/
│   └── commands/
│       └── create_superuser_with_password.py
├── overrides/
│   └── README.md
├── paperless.conf.example
├── presentation/
│   ├── README.md
│   ├── contrib/
│   │   ├── font-awesome-4.3.0/
│   │   │   ├── css/
│   │   │   │   └── font-awesome.css
│   │   │   ├── fonts/
│   │   │   │   └── FontAwesome.otf
│   │   │   ├── less/
│   │   │   │   ├── animated.less
│   │   │   │   ├── bordered-pulled.less
│   │   │   │   ├── core.less
│   │   │   │   ├── fixed-width.less
│   │   │   │   ├── font-awesome.less
│   │   │   │   ├── icons.less
│   │   │   │   ├── larger.less
│   │   │   │   ├── list.less
│   │   │   │   ├── mixins.less
│   │   │   │   ├── path.less
│   │   │   │   ├── rotated-flipped.less
│   │   │   │   ├── stacked.less
│   │   │   │   └── variables.less
│   │   │   └── scss/
│   │   │       ├── _animated.scss
│   │   │       ├── _bordered-pulled.scss
│   │   │       ├── _core.scss
│   │   │       ├── _fixed-width.scss
│   │   │       ├── _icons.scss
│   │   │       ├── _larger.scss
│   │   │       ├── _list.scss
│   │   │       ├── _mixins.scss
│   │   │       ├── _path.scss
│   │   │       ├── _rotated-flipped.scss
│   │   │       ├── _stacked.scss
│   │   │       ├── _variables.scss
│   │   │       └── font-awesome.scss
│   │   └── google/
│   │       └── css/
│   │           └── lato.css
│   ├── css/
│   │   ├── print/
│   │   │   ├── paper.css
│   │   │   └── pdf.css
│   │   ├── reveal.css
│   │   ├── reveal.scss
│   │   └── theme/
│   │       ├── README.md
│   │       ├── beige.css
│   │       ├── black.css
│   │       ├── blood.css
│   │       ├── league.css
│   │       ├── moon.css
│   │       ├── night.css
│   │       ├── serif.css
│   │       ├── simple.css
│   │       ├── sky.css
│   │       ├── solarized.css
│   │       ├── source/
│   │       │   ├── beige.scss
│   │       │   ├── black.scss
│   │       │   ├── blood.scss
│   │       │   ├── league.scss
│   │       │   ├── moon.scss
│   │       │   ├── night.scss
│   │       │   ├── serif.scss
│   │       │   ├── simple.scss
│   │       │   ├── sky.scss
│   │       │   ├── solarized.scss
│   │       │   └── white.scss
│   │       ├── template/
│   │       │   ├── mixins.scss
│   │       │   ├── settings.scss
│   │       │   └── theme.scss
│   │       └── white.css
│   ├── index.html
│   ├── js/
│   │   └── reveal.js
│   ├── lib/
│   │   ├── css/
│   │   │   └── zenburn.css
│   │   ├── font/
│   │   │   ├── league-gothic/
│   │   │   │   ├── LICENSE
│   │   │   │   └── league-gothic.css
│   │   │   └── source-sans-pro/
│   │   │       ├── LICENSE
│   │   │       └── source-sans-pro.css
│   │   └── js/
│   │       ├── classList.js
│   │       └── html5shiv.js
│   └── plugin/
│       ├── highlight/
│       │   └── highlight.js
│       ├── leap/
│       │   └── leap.js
│       ├── markdown/
│       │   ├── example.html
│       │   ├── example.md
│       │   ├── markdown.js
│       │   └── marked.js
│       ├── math/
│       │   └── math.js
│       ├── multiplex/
│       │   ├── client.js
│       │   ├── index.js
│       │   └── master.js
│       ├── notes/
│       │   ├── notes.html
│       │   └── notes.js
│       ├── notes-server/
│       │   ├── client.js
│       │   ├── index.js
│       │   └── notes.html
│       ├── print-pdf/
│       │   └── print-pdf.js
│       ├── remotes/
│       │   └── remotes.js
│       ├── search/
│       │   └── search.js
│       └── zoom-js/
│           └── zoom.js
├── requirements.txt
├── resources/
│   └── logo/
│       └── print/
│           └── eps/
│               ├── Black logo - no background.eps
│               ├── Color logo - no background.eps
│               ├── Color logo with background.eps
│               └── White logo - no background.eps
├── scripts/
│   ├── docker-entrypoint.sh
│   ├── gunicorn.conf
│   ├── paperless-consumer.service
│   ├── paperless-webserver.service
│   └── post-consumption-example.sh
└── src/
    ├── documents/
    │   ├── __init__.py
    │   ├── actions.py
    │   ├── admin.py
    │   ├── apps.py
    │   ├── checks.py
    │   ├── consumer.py
    │   ├── filters.py
    │   ├── forms.py
    │   ├── loggers.py
    │   ├── mail.py
    │   ├── management/
    │   │   ├── __init__.py
    │   │   └── commands/
    │   │       ├── __init__.py
    │   │       ├── change_storage_type.py
    │   │       ├── document_consumer.py
    │   │       ├── document_correspondents.py
    │   │       ├── document_exporter.py
    │   │       ├── document_importer.py
    │   │       ├── document_logs.py
    │   │       ├── document_renamer.py
    │   │       ├── document_retagger.py
    │   │       └── loaddata_stdin.py
    │   ├── managers.py
    │   ├── migrations/
    │   │   ├── 0001_initial.py
    │   │   ├── 0002_auto_20151226_1316.py
    │   │   ├── 0003_sender.py
    │   │   ├── 0004_auto_20160114_1844.py
    │   │   ├── 0005_auto_20160123_0313.py
    │   │   ├── 0006_auto_20160123_0430.py
    │   │   ├── 0007_auto_20160126_2114.py
    │   │   ├── 0008_document_file_type.py
    │   │   ├── 0009_auto_20160214_0040.py
    │   │   ├── 0010_log.py
    │   │   ├── 0011_auto_20160303_1929.py
    │   │   ├── 0012_auto_20160305_0040.py
    │   │   ├── 0013_auto_20160325_2111.py
    │   │   ├── 0014_document_checksum.py
    │   │   ├── 0015_add_insensitive_to_match.py
    │   │   ├── 0016_auto_20170325_1558.py
    │   │   ├── 0017_auto_20170512_0507.py
    │   │   ├── 0018_auto_20170715_1712.py
    │   │   ├── 0019_add_consumer_user.py
    │   │   ├── 0020_document_added.py
    │   │   ├── 0021_document_storage_type.py
    │   │   ├── 0022_auto_20181007_1420.py
    │   │   ├── 0023_document_current_filename.py
    │   │   └── __init__.py
    │   ├── mixins.py
    │   ├── models.py
    │   ├── parsers.py
    │   ├── serialisers.py
    │   ├── settings.py
    │   ├── signals/
    │   │   ├── __init__.py
    │   │   └── handlers.py
    │   ├── static/
    │   │   ├── js/
    │   │   │   └── colours.js
    │   │   └── paperless.css
    │   ├── templates/
    │   │   ├── admin/
    │   │   │   ├── base_site.html
    │   │   │   ├── documents/
    │   │   │   │   └── document/
    │   │   │   │       ├── change_form.html
    │   │   │   │       ├── change_list.html
    │   │   │   │       ├── change_list_results.html
    │   │   │   │       └── select_object.html
    │   │   │   └── index.html
    │   │   └── documents/
    │   │       └── index.html
    │   ├── templatetags/
    │   │   ├── __init__.py
    │   │   ├── customisation.py
    │   │   └── hacks.py
    │   ├── tests/
    │   │   ├── __init__.py
    │   │   ├── factories.py
    │   │   ├── samples/
    │   │   │   ├── inline_mail.txt
    │   │   │   └── mail.txt
    │   │   ├── test_checks.py
    │   │   ├── test_consumer.py
    │   │   ├── test_document_model.py
    │   │   ├── test_file_handling.py
    │   │   ├── test_importer.py
    │   │   ├── test_logger.py
    │   │   ├── test_mail.py
    │   │   ├── test_matchables.py
    │   │   └── test_models.py
    │   └── views.py
    ├── manage.py
    ├── paperless/
    │   ├── __init__.py
    │   ├── checks.py
    │   ├── db.py
    │   ├── middleware.py
    │   ├── mixins.py
    │   ├── models.py
    │   ├── settings.py
    │   ├── urls.py
    │   ├── version.py
    │   ├── views.py
    │   └── wsgi.py
    ├── paperless_tesseract/
    │   ├── __init__.py
    │   ├── apps.py
    │   ├── languages.py
    │   ├── parsers.py
    │   ├── signals.py
    │   └── tests/
    │       ├── __init__.py
    │       ├── test_date.py
    │       ├── test_ocr.py
    │       └── test_signals.py
    ├── paperless_text/
    │   ├── __init__.py
    │   ├── apps.py
    │   ├── parsers.py
    │   └── signals.py
    ├── reminders/
    │   ├── __init__.py
    │   ├── admin.py
    │   ├── apps.py
    │   ├── filters.py
    │   ├── migrations/
    │   │   ├── 0001_initial.py
    │   │   ├── 0002_auto_20181007_1420.py
    │   │   └── __init__.py
    │   ├── models.py
    │   ├── serialisers.py
    │   ├── tests.py
    │   └── views.py
    ├── setup.cfg
    └── tox.ini

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

================================================
FILE: .docker-hub-test
================================================
Docker Hub test 2


================================================
FILE: .editorconfig
================================================
# EditorConfig: http://EditorConfig.org

root = true

[*]
indent_style = tab
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
end_of_line = lf
charset = utf-8
max_line_length = 79

[{*.html,*.css,*.js}]
max_line_length = off

[*.py]
indent_size = 4
indent_style = space

[*.yml]
indent_style = space

# Tests don't get a line width restriction.  It's still a good idea to follow
# the 79 character rule, but in the interests of clarity, tests often need to
# violate it.
[**/test_*.py]
max_line_length = off


================================================
FILE: .gitattributes
================================================
THANKS.md merge=union


================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
#lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.pytest_cache

# Translations
*.mo
*.pot

# Django stuff:
*.log

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Stored PDFs
media/documents/*.gpg
media/documents/thumbnails/*
media/documents/originals/*
media/overrides.css
media/overrides.js

# Sqlite database
db.sqlite3
db.sqlite3-journal

# PyCharm
.idea

# Other stuff that doesn't belong
.virtualenv
virtualenv
docker-compose.yml
docker-compose.env

# Used for development
scripts/import-for-development
scripts/nuke

# Static files collected by the collectstatic command
./static/


================================================
FILE: .travis.yml
================================================
language: python

before_install:
- sudo apt-get update -qq
- sudo apt-get install -qq libpoppler-cpp-dev unpaper tesseract-ocr imagemagick ghostscript optipng

sudo: false

matrix:
    include:        
        - python: "3.5"
        - python: "3.6"
        - python: "3.7-dev"
        - env:
            - BUILD_DOCKER=1
            # Variable to add to publish the Docker image:
            # * DOCKER_USERNAME
            # * DOCKER_PASSWORD, to be encrypted, use `travis encrypt DOCKER_PASSWORD=<password>`
          services:
            - docker
          before_install:
            - true
          install:
            - true
          script:
            - docker build --tag=the-paperless-project/paperless .
          after_success:
            - true

install:
    - pip install --upgrade pip pipenv sphinx
    - pipenv lock -r > requirements.txt
    - pip install -r requirements.txt

script:
    - cd src/
    - pytest --cov
    - pycodestyle
    - sphinx-build -b html ../docs ../docs/_build -W

after_success:
  - coveralls

deploy:
  - provider: script
    skip_cleanup: true
    script: ci/deploy-docker
    on:
      tags: true
      condition: '"${BUILD_DOCKER}" = 1'
  - provider: script
    skip_cleanup: true
    script: ci/deploy-docker
    on:
      branch: master
      condition: '"${BUILD_DOCKER}" = 1'


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* Unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at code@danielquinn.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4 to remove puritanical language.  The original is available at [http://contributor-covenant.org/version/1/4][version]

[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/


================================================
FILE: Dockerfile
================================================
FROM alpine:3.12

LABEL maintainer="The Paperless Project https://github.com/the-paperless-project/paperless" \
      contributors="Guy Addadi <addadi@gmail.com>, Pit Kleyersburg <pitkley@googlemail.com>, \
        Sven Fischer <git-dev@linux4tw.de>"

# Copy Pipfiles file, init script and gunicorn.conf
COPY Pipfile* /usr/src/paperless/
COPY scripts/docker-entrypoint.sh /sbin/docker-entrypoint.sh
COPY scripts/gunicorn.conf /usr/src/paperless/

# Set export and consumption directories
ENV PAPERLESS_EXPORT_DIR=/export \
    PAPERLESS_CONSUMPTION_DIR=/consume

RUN apk add --no-cache \
      bash \
      curl \
      ghostscript \
      gnupg \
      imagemagick \
      libmagic \
      libpq \
      optipng \
      poppler \
      python3 \
      shadow \
      sudo \
      tesseract-ocr \
			tzdata \
      unpaper && \
    apk add --no-cache --virtual .build-dependencies \
      g++ \
      gcc \
      jpeg-dev \
      musl-dev \
      poppler-dev \
      postgresql-dev \
      python3-dev \
      zlib-dev && \
# Install python dependencies
    python3 -m ensurepip && \
    rm -r /usr/lib/python*/ensurepip && \
    cd /usr/src/paperless && \
    pip3 install --upgrade pip pipenv && \
    pipenv install --system --deploy && \
# Remove build dependencies
    apk del .build-dependencies && \
# Create the consumption directory
    mkdir -p $PAPERLESS_CONSUMPTION_DIR && \
# Create user
    addgroup -g 1000 paperless && \
    adduser -D -u 1000 -G paperless -h /usr/src/paperless paperless && \
    chown -Rh paperless:paperless /usr/src/paperless && \
    mkdir -p $PAPERLESS_EXPORT_DIR && \
# Avoid setrlimit warnings
# See: https://gitlab.alpinelinux.org/alpine/aports/issues/11122
    echo 'Set disable_coredump false' >> /etc/sudo.conf && \
# Setup entrypoint
    chmod 755 /sbin/docker-entrypoint.sh

WORKDIR /usr/src/paperless/src
# Mount volumes and set Entrypoint
VOLUME ["/usr/src/paperless/data", "/usr/src/paperless/media", "/consume", "/export"]
ENTRYPOINT ["/sbin/docker-entrypoint.sh"]
CMD ["--help"]

# Copy application
COPY src/ /usr/src/paperless/src/
COPY data/ /usr/src/paperless/data/
COPY media/ /usr/src/paperless/media/

# Collect static files
RUN sudo -HEu paperless /usr/src/paperless/src/manage.py collectstatic --clear --no-input


================================================
FILE: LICENSE
================================================
                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.

  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.

  Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so.  This is fundamentally incompatible with the aim of
protecting users' freedom to change the software.  The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable.  Therefore, we
have designed this version of the GPL to prohibit the practice for those
products.  If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.

  Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary.  To prevent this, the GPL assures that
patents cannot be used to render the program non-free.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Use with the GNU Affero General Public License.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    {one line to give the program's name and a brief idea of what it does.}
    Copyright (C) {year}  {name of author}

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU 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 General Public License for more details.

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

Also add information on how to contact you by electronic and paper mail.

  If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:

    {project}  Copyright (C) {year}  {fullname}
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.

  The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.



================================================
FILE: Pipfile
================================================
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"

[packages]
django = "<2.1,>=2.0"
pillow = "*"
coveralls = "*"
dateparser = "*"
django-cors-headers = "*"
django-crispy-forms = "*"
django-extensions = "*"
django-filter = "*"
djangorestframework = "*"
factory-boy = "*"
filemagic = "*"
fuzzywuzzy = {extras = ["speedup"],version = "==0.15.0"}
gunicorn = "*"
inotify-simple = "*"
langdetect = "*"
pdftotext = "*"
pyocr = "*"
python-dateutil = "*"
python-dotenv = "*"
python-gnupg = "*"
pytz = "*"
sphinx = "*"
tox = "*"
pycodestyle = "*"
pytest = "*"
pytest-cov = "*"
pytest-django = "*"
pytest-sugar = "*"
pytest-env = "*"
pytest-xdist = "*"
psycopg2 = "*"
djangoql = "*"
whitenoise = "*"
brotli = "*"

[dev-packages]
ipython = "*"


================================================
FILE: README-de.md
================================================
[ [en](README.md) | de | [el](README-el.md) ]

![Paperless](https://raw.githubusercontent.com/the-paperless-project/paperless/master/src/paperless/static/paperless/img/logo-dark.png)

[![Dokumentation](https://readthedocs.org/projects/paperless/badge/?version=latest)](https://paperless.readthedocs.org/) [![Chat](https://badges.gitter.im/the-paperless-project/paperless.svg)](https://gitter.im/danielquinn/paperless) [![Travis](https://travis-ci.org/the-paperless-project/paperless.svg?branch=master)](https://travis-ci.org/the-paperless-project/paperless) [![Coverage Status](https://coveralls.io/repos/github/the-paperless-project/paperless/badge.svg?branch=master)](https://coveralls.io/github/the-paperless-project/paperless?branch=master) [![Danke](https://img.shields.io/badge/THANKS-md-ff69b4.svg)](https://github.com/the-paperless-project/paperless/blob/master/THANKS.md)

Indexiere und archiviere alle deine eingescannten Papierdokumente

Ich hasse Papier. Abgesehen von Umweltproblemen, ist es der Albtraum einer technisch-interessierten Person:

* Es gibt keine Suchfunktion
* Es braucht physischen Platz
* Sicherungen bedeuten mehr Papier

In den vergangenen Monaten hatte ich mehrmals das Problem, das richtige Dokument nicht zur Hand zu haben. Manchmal warf ich Dokumente weg, die ich noch gebraucht hätte (wer behält schon Wasserrechnungen für zwei Jahre?), andere verlor ich einfach... weil PAPIER. Ich schrieb dies, um mein Leben einfacher zu machen.



## Wie es funktioniert

Paperless steuert nicht deinen Scanner, es hilft nur damit umzugehen, was der Scanner herausspuckt

1. Kaufe einen Dokumentenscanner, der an einen Ort in deinem Netzwerk schreiben kann. Wenn du Inspirationen brauchst, schau in die [Scannerempfehlungen](https://paperless.readthedocs.io/en/latest/scanners.html).
2. Stelle "Scanne zu FTP" oder ähnliches ein. Es sollte möglich sein, eingescannte Bilder ohne etwas tun zu müssen an einen Server hochzuladen. Natürlich kannst du auch die einscannte Datei händisch hochladen, wenn der Scanner automatisches Hochladen nicht unterstützt. Paperless ist es egal, wie die Dokumente in seinen lokalen Konsumordner gelangen.
3. Besitze einen Zielserver, lasse das Paperless-Konsumskript laufen, um die Datei mit OCR zu versehen und sie in einer lokalen Datenbank zu indexieren.
4. Benutze die Weboberfläche, um die Datenbank zu durchforsten und zu finden, was du suchst.
5. Lade die PDF-Datei, die du brauchst/möchtest über die Weboberfläche herunter und mach was auch immer du willst damit.  Du kannst es auch drucken und versenden, so als wäre es das Original. In den meisten Fällen wird das niemanden interessieren oder bemerken.

Hier das, was du bekommt:

![Vorher und Nachher](https://raw.githubusercontent.com/the-paperless-project/paperless/master/docs/_static/screenshot.png)


## Dokumentation

Diese ist komplett verfügbar auf [ReadTheDocs](https://paperless.readthedocs.org/).


## Anforderungen

Dies alles ist eine wirklich ziemlich einfache, glänzende und benutzerfreundliche Hülle rund um einige sehr mächtige Werkzeuge.

* [ImageMagick](http://imagemagick.org/) wandelt Bilder zwischen Farbe und Graustufen um.
* [Tesseract](https://github.com/tesseract-ocr) erledigt die Buchstabenerkennung.
* [Unpaper](https://github.com/unpaper/unpaper) bereinigt und begradigt das eingescannte Bild.
* [GNU Privacy Guard](https://gnupg.org/) wird als Verschlüsselungsbackend genutzt.
* [Python 3](https://python.org/) ist die Sprache des Projekts.
  * [Pillow](https://pypi.python.org/pypi/pillowfight/) lädt die Bilddaten als Python-Objekt, um sie mit PyOCR zu verwenden.
  * [PyOCR](https://github.com/jflesch/pyocr) ist ein glatter, programmatischer Wrapper um Tesseract.
  * [Django](https://www.djangoproject.com/) ist das Framework, auf das dieses Projekt aufbaut.
  * [Python-GNUPG](http://pythonhosted.org/python-gnupg/) entschlüsselt die PDFs auf Abruf, um das Herunterladen unverschlüsselter Dateien zu ermöglichen, während die verschlüsselten Dateien auf der Festplatte bleiben.


## Status des Projekts

Dieses Projekt wurde um 2015 gestartet und es gibt viele Leute, die es verwenden. Warum auch immer ist es ziemlich beliebt in Deutschland -- vielleicht kann jemand dort drüben mich über das Warum aufklären.

Ich entwickle keine neuen Funktionen mehr für Paperless, weil es genau das tut, was ich brauche und meine Aufmerksamkeit meinem neuesten Projekt [Aletheia](https://github.com/danielquinn/aletheia) gewidmet ist. Ich verlasse jedoch nicht das Projekt. Ich bin glücklich damit, Pull Requests zu begutachten und Fragen im Issue-Bereich zu beantworten. Wenn du ein Entwickler bist und eine neue Funktion willst, reihe sie in den Issues ein und/oder sende einen PR! Ich bin glücklich damit, neue Sachen hinzuzufügen, habe aber einfach nicht die Zeit, sie selbst zu erarbeiten.


## Verknüpfte Projekte

Paperless gibt es bereits seit einer Weile und Leute haben damit angefangen, Sachen rund um Paperless zu entwickeln. Wenn du einer dieser Menschen bist, kannst du dein Projekt zu dieser Liste hinzufügen:

* [Paperless App](https://github.com/bauerj/paperless_app): Eine Android/iOS-App für Paperless.
* [Paperless Desktop](https://github.com/thomasbrueggemann/paperless-desktop): Eine Desktop-Oberfläche für deine Paperless-Installation. Läuft auf Mac, Linux und Windows.
* [ansible-role-paperless](https://github.com/ovv/ansible-role-paperless): Eine einfache Möglichkeit, Paperless via Ansible laufen zu lassen.
* [paperless-cli](https://github.com/stgarf/paperless-cli): Ein golang Kommandozeilenprogramm, welches mit Paperless interagiert.


## Ähnliche Projekte

Es gibt da draußen auch das Projekt [Mayan EDMS](https://mayan.readthedocs.org/en/latest/), welches überraschenderweise sehr große überschneidende Techniken hat wie Paperless. Mayan EDMS ist *viel* funktionsreicher und kommt ebenso mit einer glatten UI, aber kommt noch mit Python2; basiert jedoch auch auf Django und verwendet ein Konsummodell mit Tesseract und Unpaper. Es kann sein, dass Paperless weniger Ressourcen verbraucht, aber um ehrlich zu sein, hab ich das noch nicht selbst getestet. Eine Sache jedoch ist klar, *Paperless* ist ein **viel** besserer Name.


## Wichtiger Hinweis

Dokumentenscanner werden typischerweise verwendet, um sensible Dokumente zu scannen. Dinge wie die Sozialversicherungsnummer, Steueraufzeichnungen, Rechnungen, etc. Während Paperless die Originaldateien über das Konsumskript verschlüsselt, sind die OCR-Texte *nicht* verschlüsselt und demnach in Klartext gespeichert (es muss durchsuchbar sein, also wenn jemand eine Idee hat, wie man das mit verschlüsselten Daten tun kann: Ich bin ganz Ohr). Das bedeutet, dass Paperless niemals auf einem nicht vertrauten Host laufen sollte. Stattdessen empfehle ich, wenn du es verwenden willst, es lokal auf einem Server in deinem Zuhause laufen zu lassen.


## Spenden

Wie mit aller Freier Software, liegt die Macht weniger in den Finanzen als mehr in den gemeinsamen Bemühungen. Ich schätze wirklich jeden Pull Request und Bugreport, der von Benutzern von Paperless getätigt wird, also bitte macht damit weiter. Wenn du jedoch nicht einer für Programmieren/Design/Dokumentation bist und mich wirklich finanziell unterstützen willst, sage ich nicht nein dazu ;-)

Das Ding ist, mir geht es finanziell OK, also würde ich dich darum bitten, an den [Hochkommissar der Vereinten Nationen für Flüchtlinge](https://donate.unhcr.org/int-en/general) zu spenden. Diese machen wichtige Arbeit und brauchen das Geld viel dringender als ich.


================================================
FILE: README-el.md
================================================
[ [en](README.md) | [de](README-de.md) | el ]

![Paperless](https://raw.githubusercontent.com/the-paperless-project/paperless/master/src/paperless/static/paperless/img/logo-dark.png)

[![Documentation](https://readthedocs.org/projects/paperless/badge/?version=latest)](https://paperless.readthedocs.org/) [![Chat](https://badges.gitter.im/the-paperless-project/paperless.svg)](https://gitter.im/danielquinn/paperless) [![Travis](https://travis-ci.org/the-paperless-project/paperless.svg?branch=master)](https://travis-ci.org/the-paperless-project/paperless) [![Coverage Status](https://coveralls.io/repos/github/the-paperless-project/paperless/badge.svg?branch=master)](https://coveralls.io/github/the-paperless-project/paperless?branch=master) [![Thanks](https://img.shields.io/badge/THANKS-md-ff69b4.svg)](https://github.com/the-paperless-project/paperless/blob/master/THANKS.md)

Ευρετήριο και αρχείο για όλα σας τα σκαναρισμένα έγγραφα

Μισώ το χαρτί. Πέρα από τα περιβαλλοντικά ζητήματα, είναι ο εφιάλτης ενός τεχνικού.

* Δεν υπάρχει η δυνατότητα της αναζήτησης
* Πιάνουν πολύ χώρο
* Τα αντίγραφα ασφαλείας σημάινουν περισσότερο χαρτί

Τους τελευταίους μήνες μου έχει τύχει αρκετές φορές να μην μπορώ να βρω το σωστό έγγραφο. Κάποιες φορές ανακύκλωνα το έγγραφο που χρειαζόμουν (ποιος κρατάει τους λογαριασμούς του νερού για 2 χρόνια;;;) και κάποιες φορές απλά το έχανα ... επειδή έτσι είναι τα χαρτιά. Το έκανα αυτό για να κάνω την ζωή μου πιο εύκολη


## Πως δουλεύει

Η εφαρμογή Paperless δεν ελέγχει το scanner σας, αλλά σας βοηθάει με τα αποτελέσματα του scanner σας.

1. Αγοράστε ένα scanner με πρόσβαση στο δίκτυο σας.  Αν χρειάζεστε έμπνευση, δείτε την σελίδα με τα [προτεινόμενα scanner](https://paperless.readthedocs.io/en/latest/scanners.html).
2. Κάντε την ρύθμιση "scan to FTP" ή κάτι παρόμοιο. Θα μπορεί να αποθηκεύει τις σκαναρισμένες εικόνες σε έναν server χωρίς να χρειάζεται να κάνετε κάτι. Φυσικά άμα το scanner σας δεν μπορεί να αποθηκεύσει κάπου τις εικόνες σας αυτόματα μπορείτε να το κάνετε χειροκίνητα. Το Paperless δεν ενδιαφέρεται πως καταλήγουν κάπου τα αρχεία.
3. Να έχετε τον server που τρέχει το OCR script του Paperless να έχει ευρετήριο στην τοπική βάση δεδομένων.
4. Χρησιμοποιήστε το web frontend για να επιλέξετε βάση δεδομένων και να βρείτε αυτό που θέλετε.
5. Κατεβάστε το PDF που θέλετε/χρειάζεστε μέσω του web interface και κάντε ότι θέλετε με αυτό. Μπορείτε ακόμη να το εκτυπώσετε και να το στείλετε, σαν να ήταν το αρχικό. Στις περισσότερες περιπτώσεις κανείς δεν θα το προσέξει ή θα νοιαστεί.

Αυτό είναι που θα πάρετε:

![Το πριν και το μετά](https://raw.githubusercontent.com/the-paperless-project/paperless/master/docs/_static/screenshot.png)


## Documentation

Είναι όλα διαθέσιμα εδώ [ReadTheDocs](https://paperless.readthedocs.org/).


## Απαιτήσεις

Όλα αυτά είναι πολύ απλά, και φιλικά προς τον χρήστη, μια συλλογή με πολύτιμα εργαλεία.

* [ImageMagick](http://imagemagick.org/) μετατρέπει τις εικόνες σε έγχρωμες και ασπρόμαυρες.
* [Tesseract](https://github.com/tesseract-ocr) κάνει την αναγνώρηση των χαρακτήρων.
* [Unpaper](https://github.com/unpaper/unpaper) despeckles and deskews the scanned image.
* [GNU Privacy Guard](https://gnupg.org/) χρησιμοποιείται για κρυπτογράφηση στο backend.
* [Python 3](https://python.org/) είναι η γλώσσα του project.
  * [Pillow](https://pypi.python.org/pypi/pillowfight/) Φορτώνει την εικόνα σαν αντικείμενο στην python και μπορεί να χρησιμοποιηθεί με PyOCR
  * [PyOCR](https://github.com/jflesch/pyocr) is a slick programmatic wrapper around tesseract.
  * [Django](https://www.djangoproject.com/) το framework με το οποίο έγινε το project.
  * [Python-GNUPG](http://pythonhosted.org/python-gnupg/) Αποκρυπτογραφεί τα PDF αρχεία στη στιγμή ώστε να κατεβάζετε αποκρυπτογραφημένα αρχεία, αφήνοντας τα κρυπτογραφημένα στον δίσκο.


## Σταθερότητα

Αυτό το project υπάρχει από το 2015 και υπάρχουν αρκετοί άνθρωποι που το χρησιμοποιούν, παρόλα αυτά βρίσκεται σε διαρκή ανάπτυξη (απλά δείτε πότε commit έχουν γίνει στο git history) οπότε μην περιμένετε να είναι 100% σταθερό. Μπορείτε να κάνετε backup την βάση δεδομένων sqlite3, τον φάκελο media και το configuration αρχείο σας ώστε να είστε ασφαλείς.


## Affiliated Projects

Το Paperless υπάρχει εδώ και κάποιο καιρό και άνθρωποι έχουν αρχίσει να φτιάχνουν πράγματα γύρω από αυτό. Αν είσαι ένας από αυτούς τους ανθρώπους, μπορούμε να βάλουμε το project σου σε αυτήν την λίστα:

* [Paperless App](https://github.com/bauerj/paperless_app): Μια εφαρμογή Android / iOS για Paperless.
* [Paperless Desktop](https://github.com/thomasbrueggemann/paperless-desktop): Μια desktop εφαρμογή για εγκατάσταση του Paperless.  Τρέχει σε Mac, Linux, και Windows.
* [ansible-role-paperless](https://github.com/ovv/ansible-role-paperless): Ένας εύκολο τρόπος για να τρέχει το Paperless μέσω Ansible.


## Παρόμοια Projects

Υπάρχει ένα άλλο ṕroject που λέγεται [Mayan EDMS](https://mayan.readthedocs.org/en/latest/) το οποίο έχει παρόμοια τεχνικά χαρακτηριστικά με το Paperless σε εντυπωσιακό βαθμό.  Επίσης βασισμένο στο Django και χρησιμοποιώντας το consumer model με Tesseract και Unpaper, Mayan EDMS έχει *πολλά* περισσότερα χαρακτηριστικά και έρχεται με ένα επιδέξιο UI, αλλά είναι ακόμα σε Python 2. Μπορεί να είναι ότι το Paperless καταναλώνει λιγότερους πόρους, αλλά για να είμαι ειλικρινής, αυτό είναι μια εικασία την οποία δεν έχω επιβεβαιώσει μόνος μου.  Ένα πράγμα είναι σίγουρο, το *Paperless* έχει **πολύ** καλύτερο όνομα.


## Σημαντική Σημείωση

Τα scanner για αρχεία συνήθως χρησιμοποιούνται για ευαίσθητα αρχεία. Πράγματα όπως το ΑΜΚΑ, φορολογικά αρχεία, τιμολόγια κτλπ. Παρόλο που το Paperless κρυπτογραφεί τα αρχικά αρχεία μέσω του consumption script, το κείμενο OCR *δεν είναι* κρυπτογραφημένο και για αυτό αποθηκεύεται (πρέπει να είναι αναζητήσιμο, οπότε αν κάποιος ξέρει να το κάνει αυτό με κρυπτογραφημένα δεδομένα είμαι όλος αυτιά). Αυτό σημάνει ότι το Paperless δεν πρέπει ποτέ να τρέχει σε μη αξιόπιστο πάροχο. Για αυτό συστήνω αν θέλετε να το τρέξετε να το τρέξετε σε έναν τοπικό server σπίτι σας.


## Δωρεές

Όπως με όλα τα δωρεάν λογισμικά, η δύναμη δεν βρίσκεται στα οικονομικά αλλά στην συλλογική προσπάθεια. Αλήθεια εκτιμώ κάθε pull request και bug report που προσφέρεται από τους χρήστες του Paperless, οπότε σας παρακαλώ συνεχίστε. Αν παρόλα αυτά, δεν μπορείτε να γράψετε κώδικα/να κάνέτε design/να γράψετε documentation, και θέλετε να συνεισφέρετε οικονομικά, δεν θα πω όχι ;-)

Το θέμα είναι ότι είμαι οικονομικά εντάξει, οπότε θα σας ζητήσω να δωρίσετε τα χρήματα σας εδώ [United Nations High Commissioner for Refugees](https://donate.unhcr.org/int-en/general). Κάνουν σημαντική δουλειά και χρειάζονται τα χρήματα πολύ περισσότερο από ότι εγώ.


================================================
FILE: README.md
================================================
[ en | [de](README-de.md) | [el](README-el.md) ]

![Paperless](https://raw.githubusercontent.com/the-paperless-project/paperless/master/src/paperless/static/paperless/img/logo-dark.png)

> ## Important news about the future of this project
> 
> It's been more than 5 years since I started this project on a whim as an effort to try to get a handle on the massive amount of paper I was dealing with in relation to various visa applications (expat life is complicated!)  Since then, the project has *exploded* in popularity, so much so that it overwhelmed me and working on it stopped being "fun" and started becoming a serious source of stress.
> 
> In an effort to fix this, I created the Paperless GitHub [organisation](https://github.com/the-paperless-project), and brought on a few people to manage the issue and pull request load.  Unfortunately, that model has proven to be unworkable too.  With 23 pull requests waiting and 157 issues slowly filling up with confused/annoyed people wanting to get their contributions in, my whole "appoint a few strangers and hope they've got time" idea is showing my lack of foresight and organisational skill.
> 
> In the shadow of these difficulties, a fork called [Paperless-ng](https://github.com/jonaswinkler/paperless-ng) written by [Jonas Winkler](https://github.com/jonaswinkler) has cropped up.  It's *really* good, and unlike this project, it's actively maintained (at the time of this writing anyway).  With 564 forks currently tracked by GitHub, I suspect there are a few more forks worth looking into out there as well.
> 
> So, with all of the above in mind, I've decided to archive this project as read-only and suggest that those interested in new updates or submitting patches have a look at Paperless-ng.  If you really like "Old Paperless", that's ok too!  The project is [GPL licensed](https://github.com/the-paperless-project/paperless/blob/master/LICENSE), so you can fork it and run it on whatever you like so long as you respect the terms of said license.
>
> In time, I may transfer ownership of this organisation to Jonas if he's interested in taking that on, but for the moment, he's happy to run Paperless-ng out of its [current repo](https://github.com/jonaswinkler/paperless-ng).  Regardless, if we do decide to make the transfer, I'll post a notification here a few months in advance so that people won't be surprised by new code at this location.
> 
> For my part, I'm really happy & proud to have been part of this project, and I'm sorry I've been unable to commit more time to it for everyone.  I hope you all understand, and I'm really pleased that this work has been able to continue to live and be useful in a new project.  Thank you to everyone who contributed, and for making Free software awesome.
> 
> Sincerely,
> [Daniel Quinn](https://github.com/danielquinn)


[![Documentation](https://readthedocs.org/projects/paperless/badge/?version=latest)](https://paperless.readthedocs.org/)
[![Chat](https://badges.gitter.im/the-paperless-project/paperless.svg)](https://gitter.im/danielquinn/paperless)
[![Travis](https://travis-ci.org/the-paperless-project/paperless.svg?branch=master)](https://travis-ci.org/the-paperless-project/paperless)
[![Coverage Status](https://coveralls.io/repos/github/the-paperless-project/paperless/badge.svg?branch=master)](https://coveralls.io/github/the-paperless-project/paperless?branch=master)
[![StackShare](https://img.shields.io/badge/tech-stack-0690fa.svg?style=flat)](https://stackshare.io/the-paperless-project/the-paperless-project)
[![Thanks](https://img.shields.io/badge/THANKS-md-ff69b4.svg)](https://github.com/the-paperless-project/paperless/blob/master/THANKS.md)

Index and archive all of your scanned paper documents

I hate paper.  Environmental issues aside, it's a tech person's nightmare:

* There's no search feature
* It takes up physical space
* Backups mean more paper

In the past few months I've been bitten more than a few times by the problem of not having the right document around.  Sometimes I recycled a document I needed (who keeps water bills for two years?) and other times I just lost it... because paper.  I wrote this to make my life easier.


## How it Works

Paperless does not control your scanner, it only helps you deal with what your scanner produces

1. Buy a document scanner that can write to a place on your network.  If you need some inspiration, have a look at the [scanner recommendations](https://paperless.readthedocs.io/en/latest/scanners.html) page.
2. Set it up to "scan to FTP" or something similar. It should be able to push scanned images to a server without you having to do anything.  Of course if your scanner doesn't know how to automatically upload the file somewhere, you can always do that manually.  Paperless doesn't care how the documents get into its local consumption directory.
3. Have the target server run the Paperless consumption script to OCR the file and index it into a local database.
4. Use the web frontend to sift through the database and find what you want.
5. Download the PDF you need/want via the web interface and do whatever you like with it.  You can even print it and send it as if it's the original. In most cases, no one will care or notice.

Here's what you get:

![The before and after](https://raw.githubusercontent.com/the-paperless-project/paperless/master/docs/_static/screenshot.png)


## Documentation

It's all available on [ReadTheDocs](https://paperless.readthedocs.io/).


## Requirements

This is all really a quite simple, shiny, user-friendly wrapper around some very powerful tools.

* [ImageMagick](http://imagemagick.org/) converts the images between colour and greyscale.
* [Tesseract](https://github.com/tesseract-ocr) does the character recognition.
* [Unpaper](https://github.com/unpaper/unpaper) despeckles and deskews the scanned image.
* [GNU Privacy Guard](https://gnupg.org/) is used as the encryption backend.
* [Python 3](https://python.org/) is the language of the project.
  * [Pillow](https://pypi.python.org/pypi/pillowfight/) loads the image data as a python object to be used with PyOCR.
  * [PyOCR](https://github.com/jflesch/pyocr) is a slick programmatic wrapper around tesseract.
  * [Django](https://www.djangoproject.com/) is the framework this project is written against.
  * [Python-GNUPG](http://pythonhosted.org/python-gnupg/) decrypts the PDFs on-the-fly to allow you to download unencrypted files, leaving the encrypted ones on-disk.


## Project Status

This project has been around since 2015, and there's lots of people using it.  For some reason, it's really popular in Germany -- maybe someone over there can clue me in as to why?

I am no longer doing new development on Paperless as it does exactly what I need it to and have since turned my attention to my latest project, [Aletheia](https://github.com/danielquinn/aletheia).  However, I'm not abandoning this project.  I am happy to field pull requests and answer questions in the issue queue.  If you're a developer yourself and want a new feature, float it in the issue queue and/or send me a pull request!  I'm happy to add new stuff, but I just don't have the time to do that work myself.


## Affiliated Projects

Paperless has been around a while now, and people are starting to build stuff on top of it.  If you're one of those people, we can add your project to this list:

* [Paperless App](https://github.com/bauerj/paperless_app): An Android/iOS app for Paperless.
* [Paperless Desktop](https://github.com/thomasbrueggemann/paperless-desktop): A desktop UI for your Paperless installation.  Runs on Mac, Linux, and Windows.
* [ansible-role-paperless](https://github.com/ovv/ansible-role-paperless): An easy way to get Paperless running via Ansible.
* [paperless-cli](https://github.com/stgarf/paperless-cli): A golang command line binary to interact with a Paperless instance.

## Similar Projects

There's another project out there called [Mayan EDMS](https://www.mayan-edms.com/) that has a surprising amount of technical overlap with Paperless.  Also based on Django and using a consumer model with Tesseract and Unpaper, Mayan EDMS is *much* more featureful and comes with a slick UI as well, but still in Python 2. It may be that Paperless consumes fewer resources, but to be honest, this is just a guess as I haven't tested this myself.  One thing's for certain though, *Paperless* is a **way** better name.


## Important Note

Document scanners are typically used to scan sensitive documents.  Things like your social insurance number, tax records, invoices, etc.  While Paperless encrypts the original files via the consumption script, the OCR'd text is *not* encrypted and is therefore stored in the clear (it needs to be searchable, so if someone has ideas on how to do that on encrypted data, I'm all ears).  This means that Paperless should never be run on an untrusted host.  Instead, I recommend that if you do want to use it, run it locally on a server in your own home.


## Donations

As with all Free software, the power is less in the finances and more in the collective efforts.  I really appreciate every pull request and bug report offered up by Paperless' users, so please keep that stuff coming.  If however, you're not one for coding/design/documentation, and would like to contribute financially, I won't say no ;-)

The thing is, I'm doing ok for money, so I would instead ask you to donate to the [United Nations High Commissioner for Refugees](https://donate.unhcr.org/int-en/general). They're doing important work and they need the money a lot more than I do.


================================================
FILE: THANKS.md
================================================
# Thanks for using Paperless!

Working on this project has been exhausting, but rewarding at the same time.
It's just wonderful that so many people are using this thing, and in so many
crazy ways.

This file is here for everyone to post their own stories about how you use this
code.  It helps me to understand who's using it and why, and maybe to give
others an idea of how it might be used.  It's based on a Twitter exchange
between [John Glanville](https://twitter.com/hexapodium) and
[Julia Evans](https://github.com/jvns) and later better defined [here](https://github.com/paulmolluzzo/thanks-md). 

To contribute, simply issue a pull request that appends to this file something
like this:

```
### Your Name
Some friendly message
```


================================================
FILE: ci/deploy-docker
================================================
#!/bin/bash

if [ "${DOCKER_USERNAME}" == "" -o "${DOCKER_PASSWORD}" == "" ]
then
    exit 0
fi

docker login --username=${DOCKER_USERNAME} --password=${DOCKER_PASSWORD}
if [ "${TRAVIS_TAG}" != "" ]
then
    docker tag the-paperless-project/paperless the-paperless-project/paperless:${TRAVIS_TAG}
    docker push the-paperless-project/paperless:${TRAVIS_TAG}
else
    docker push the-paperless-project/paperless
fi


================================================
FILE: data/.keep
================================================


================================================
FILE: docker-compose.env.example
================================================
# Environment variables to set for Paperless
# Commented out variables will be replaced with a default within Paperless.
#
# In addition to what you see here, you can also define any values you find in
# paperless.conf.example here.  Values like:
#
# * PAPERLESS_PASSPHRASE
# * PAPERLESS_CONSUMPTION_DIR
# * PAPERLESS_CONSUME_MAIL_HOST
#
# ...are all explained in that file but can be defined here, since the Docker
# installation doesn't make use of paperless.conf.
#
# NOTE: values in paperless.conf should be wrapped in double quotes, but not in this file
# Example:
# paperless.conf: PAPERLESS_FORGIVING_OCR="true"
# docker-compose.env (this file): PAPERLESS_FORGIVING_OCR=true

# Use this variable to set a timezone for the Paperless Docker containers. If not specified, defaults to UTC.
# TZ=America/Los_Angeles

# Additional languages to install for text recognition.  Note that this is
# different from PAPERLESS_OCR_LANGUAGE (default=eng), which defines the
# default language used when guessing the language from the OCR output.
# PAPERLESS_OCR_LANGUAGES=deu ita

# Set Paperless to use SSL for the web interface.
# Enabling this will require ssl.key and ssl.cert files in paperless' data directory.
# PAPERLESS_USE_SSL=false

# You can change the default user and group id to a custom one
# USERMAP_UID=1000
# USERMAP_GID=1000


================================================
FILE: docker-compose.yml.example
================================================
version: '2.1'

services:
    webserver:
        build: ./
        # uncomment the following line to start automatically on system boot
        # restart: always
        ports:
            # You can adapt the port you want Paperless to listen on by
            # modifying the part before the `:`.
            - "8000:8000"
        healthcheck:
            test: ["CMD", "curl" , "-f", "http://localhost:8000"]
            interval: 30s
            timeout: 10s
            retries: 5
        volumes:
            - data:/usr/src/paperless/data
            - media:/usr/src/paperless/media
            # You have to adapt the local path you want the consumption
            # directory to mount to by modifying the part before the ':'.
            - ./consume:/consume
        env_file: docker-compose.env
        # The reason the line is here is so that the webserver that doesn't do
        # any text recognition and doesn't have to install unnecessary
        # languages the user might have set in the env-file by overwriting the
        # value with nothing.
        environment:
            - PAPERLESS_OCR_LANGUAGES=
        command: ["gunicorn", "-b", "0.0.0.0:8000"]

    consumer:
        build: ./
        # uncomment the following line to start automatically on system boot
        # restart: always
        depends_on:
            webserver:
                condition: service_healthy
        volumes:
            - data:/usr/src/paperless/data
            - media:/usr/src/paperless/media
            # This should be set to the same value as the consume directory
            # in the webserver service above.
            - ./consume:/consume
            # Likewise, you can add a local path to mount a directory for
            # exporting. This is not strictly needed for paperless to
            # function, only if you're exporting your files: uncomment
            # it and fill in a local path if you know you're going to
            # want to export your documents.
            # - /path/to/another/arbitrary/place:/export
        env_file: docker-compose.env
        command: ["document_consumer"]

volumes:
    data:
    media:


================================================
FILE: docs/Dockerfile
================================================
FROM python:3.5.1
MAINTAINER Pit Kleyersburg <pitkley@googlemail.com>

# Install Sphinx and Pygments
RUN pip install Sphinx Pygments

# Setup directories, copy data
RUN mkdir /build
COPY . /build
WORKDIR /build/docs

# Build documentation
RUN make html

# Start webserver
WORKDIR /build/docs/_build/html
EXPOSE 8000/tcp
CMD ["python3", "-m", "http.server"]


================================================
FILE: docs/Makefile
================================================
# Makefile for Sphinx documentation
#

# You can set these variables from the command line.
SPHINXOPTS    =
SPHINXBUILD   = sphinx-build
PAPER         =
BUILDDIR      = _build

# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif

# Internal variables.
PAPEROPT_a4     = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .

.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext

help:
	@echo "Please use \`make <target>' where <target> is one of"
	@echo "  html       to make standalone HTML files"
	@echo "  dirhtml    to make HTML files named index.html in directories"
	@echo "  singlehtml to make a single large HTML file"
	@echo "  pickle     to make pickle files"
	@echo "  json       to make JSON files"
	@echo "  htmlhelp   to make HTML files and a HTML help project"
	@echo "  qthelp     to make HTML files and a qthelp project"
	@echo "  devhelp    to make HTML files and a Devhelp project"
	@echo "  epub       to make an epub"
	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
	@echo "  latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
	@echo "  text       to make text files"
	@echo "  man        to make manual pages"
	@echo "  texinfo    to make Texinfo files"
	@echo "  info       to make Texinfo files and run them through makeinfo"
	@echo "  gettext    to make PO message catalogs"
	@echo "  changes    to make an overview of all changed/added/deprecated items"
	@echo "  xml        to make Docutils-native XML files"
	@echo "  pseudoxml  to make pseudoxml-XML files for display purposes"
	@echo "  linkcheck  to check all external links for integrity"
	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"

clean:
	rm -rf $(BUILDDIR)/*

html:
	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
	@echo
	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."

dirhtml:
	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
	@echo
	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."

singlehtml:
	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
	@echo
	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."

pickle:
	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
	@echo
	@echo "Build finished; now you can process the pickle files."

json:
	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
	@echo
	@echo "Build finished; now you can process the JSON files."

htmlhelp:
	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
	@echo
	@echo "Build finished; now you can run HTML Help Workshop with the" \
	      ".hhp project file in $(BUILDDIR)/htmlhelp."

qthelp:
	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
	@echo
	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/RIPEAtlasToolsMagellan.qhcp"
	@echo "To view the help file:"
	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/RIPEAtlasToolsMagellan.qhc"

devhelp:
	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
	@echo
	@echo "Build finished."
	@echo "To view the help file:"
	@echo "# mkdir -p $$HOME/.local/share/devhelp/RIPEAtlasToolsMagellan"
	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/RIPEAtlasToolsMagellan"
	@echo "# devhelp"

epub:
	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
	@echo
	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."

latex:
	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
	@echo
	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
	@echo "Run \`make' in that directory to run these through (pdf)latex" \
	      "(use \`make latexpdf' here to do that automatically)."

latexpdf:
	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
	@echo "Running LaTeX files through pdflatex..."
	$(MAKE) -C $(BUILDDIR)/latex all-pdf
	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."

latexpdfja:
	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
	@echo "Running LaTeX files through platex and dvipdfmx..."
	$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."

text:
	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
	@echo
	@echo "Build finished. The text files are in $(BUILDDIR)/text."

man:
	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
	@echo
	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."

texinfo:
	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
	@echo
	@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
	@echo "Run \`make' in that directory to run these through makeinfo" \
	      "(use \`make info' here to do that automatically)."

info:
	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
	@echo "Running Texinfo files through makeinfo..."
	make -C $(BUILDDIR)/texinfo info
	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."

gettext:
	$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
	@echo
	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."

changes:
	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
	@echo
	@echo "The overview file is in $(BUILDDIR)/changes."

linkcheck:
	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
	@echo
	@echo "Link check complete; look for any errors in the above output " \
	      "or in $(BUILDDIR)/linkcheck/output.txt."

doctest:
	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
	@echo "Testing of doctests in the sources finished, look at the " \
	      "results in $(BUILDDIR)/doctest/output.txt."

xml:
	$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
	@echo
	@echo "Build finished. The XML files are in $(BUILDDIR)/xml."

pseudoxml:
	$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
	@echo
	@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."


================================================
FILE: docs/_static/.keep
================================================


================================================
FILE: docs/_static/custom.css
================================================
/* override table width restrictions */
@media screen and (min-width: 767px) {

  .wy-table-responsive table td {
    /* !important prevents the common CSS stylesheets from
       overriding this as on RTD they are loaded after this stylesheet */
    white-space: normal !important;
  }

  .wy-table-responsive {
    overflow: visible !important;
  }

}


================================================
FILE: docs/api.rst
================================================
.. _api:

The REST API
############

Paperless makes use of the `Django REST Framework`_ standard API interface
because of its inherent awesomeness.  Conveniently, the system is also
self-documenting, so to learn more about the access points, schema, what's
accepted and what isn't, you need only visit ``/api`` on your local Paperless
installation.

.. _Django REST Framework: http://django-rest-framework.org/


.. _api-uploading:

Uploading
---------

File uploads in an API are hard and so far as I've been able to tell, there's
no standard way of accepting them, so rather than crowbar file uploads into the
REST API and endure that headache, I've left that process to a simple HTTP
POST, documented on the :ref:`consumption page <consumption-http>`.


================================================
FILE: docs/changelog.rst
================================================
Changelog
#########

2.7.0
=====

* `syntonym`_ submitted a pull request to catch IMAP connection errors `#475`_.
* `Stéphane Brunner`_ added ``psycopg2`` to the Pipfile `#489`_.  He also fixed
  a syntax error in ``docker-compose.yml.example`` `#488`_ and added [DjangoQL](https://github.com/ivelum/djangoql),
  which allows a litany of handy search functionality `#492`_.
* `CkuT`_ and `JOKer`_ hacked out a simple, but super-helpful optimisation to
  how the thumbnails are served up, improving performance considerably `#481`_.
* `tsia`_ added a few fields to the tags REST API. `#483`_.
* `Brian Cribbs`_ improved the documentation to help people using Paperless
  over NFS `#484`_.
* `Brendan M. Sleight`_ updated the documentation to include a note for setting the
  ``DEBUG`` value.  The ``paperless.conf.example`` file was also updated to
  mirror the project defaults.


2.6.1
=====

* We now have a logo, complete with a favicon :-)
* Removed some problematic tests.
* Fix the docker-compose example config to include a shared consume volume so
  that using the push API will work for users of the Docker install.  Thanks to
  `Colin Frei`_ for fixing this in `#466`_.
* `khrise`_ submitted a pull request to include the ``added`` property to the
  REST API `#471`_.


2.6.0
=====

* Allow an infinite number of logs to be deleted.  Thanks to `Ulli`_ for noting
  the problem in `#433`_.
* Fix the ``RecentCorrespondentsFilter`` correspondents filter that was added
  in 2.4 to play nice with the defaults.  Thanks to `tsia`_ and `Sblop`_ who
  pointed this out. `#423`_.
* Updated dependencies to include (among other things) a security patch to
  requests.
* Fix text in sample data for tests so that the language guesser stops thinking
  that everything is in Catalan because we had *Lorem ipsum* in there.
* Tweaked the gunicorn sample command to use filesystem paths instead of Python
  paths. `#441`_
* Added pretty colour boxes next to the hex values in the Tags section, thanks
  to a pull request from `Joshua Taillon`_ `#442`_.
* Added a ``.editorconfig`` file to better specify coding style.
* `Joshua Taillon`_ also added some logic to tie Paperless' date guessing logic
  into how it parses file names on import. `#440`_


2.5.0
=====

* **New dependency**: Paperless now optimises thumbnail generation with
  `optipng`_, so you'll need to install that somewhere in your PATH or declare
  its location in ``PAPERLESS_OPTIPNG_BINARY``.  The Docker image has already
  been updated on the Docker Hub, so you just need to pull the latest one from
  there if you're a Docker user.

* "Login free" instances of Paperless were breaking whenever you tried to edit
  objects in the admin: adding/deleting tags or correspondents, or even fixing
  spelling.  This was due to the "user hack" we were applying to sessions that
  weren't using a login, as that hack user didn't have a valid id.  The fix was
  to attribute the first user id in the system to this hack user.  `#394`_

* A problem in how we handle slug values on Tags and Correspondents required a
  few changes to how we handle this field `#393`_:

  1. Slugs are no longer editable.  They're derived from the name of the tag or
     correspondent at save time, so if you wanna change the slug, you have to
     change the name, and even then you're restricted to the rules of the
     ``slugify()`` function.  The slug value is still visible in the admin
     though.
  2. I've added a migration to go over all existing tags & correspondents and
     rewrite the ``.slug`` values to ones conforming to the ``slugify()``
     rules.
  3. The consumption process now uses the same rules as ``.save()`` in
     determining a slug and using that to check for an existing
     tag/correspondent.

* An annoying bug in the date capture code was causing some bogus dates to be
  attached to documents, which in turn busted the UI.  Thanks to `Andrew Peng`_
  for reporting this. `#414`_.

* A bug in the Dockerfile meant that Tesseract language files weren't being
  installed correctly.  `euri10`_ was quick to provide a fix: `#406`_, `#413`_.

* Document consumption is now wrapped in a transaction as per an old ticket
  `#262`_.

* The ``get_date()`` functionality of the parsers has been consolidated onto
  the ``DocumentParser`` class since much of that code was redundant anyway.


2.4.0
=====

* A new set of actions are now available thanks to `jonaswinkler`_'s very first
  pull request!  You can now do nifty things like tag documents in bulk, or set
  correspondents in bulk.  `#405`_
* The import/export system is now a little smarter.  By default, documents are
  tagged as ``unencrypted``, since exports are by their nature unencrypted.
  It's now in the import step that we decide the storage type.  This allows you
  to export from an encrypted system and import into an unencrypted one, or
  vice-versa.
* The migration history has been slightly modified to accommodate PostgreSQL
  users.  Additionally, you can now tell paperless to use PostgreSQL simply by
  declaring ``PAPERLESS_DBUSER`` in your environment.  This will attempt to
  connect to your Postgres database without a password unless you also set
  ``PAPERLESS_DBPASS``.
* A bug was found in the REST API filter system that was the result of an
  update of django-filter some time ago.  This has now been patched in `#412`_.
  Thanks to `thepill`_ for spotting it!


2.3.0
=====

* Support for consuming plain text & markdown documents was added by
  `Joshua Taillon`_!  This was a long-requested feature, and it's addition is
  likely to be greatly appreciated by the community: `#395`_  Thanks also to
  `David Martin`_ for his assistance on the issue.
* `dubit0`_ found & fixed a bug that prevented management commands from running
  before we had an operational database: `#396`_
* Joshua also added a simple update to the thumbnail generation process to
  improve performance: `#399`_
* As his last bit of effort on this release, Joshua also added some code to
  allow you to view the documents inline rather than download them as an
  attachment. `#400`_
* Finally, `ahyear`_ found a slip in the Docker documentation and patched it.
  `#401`_


2.2.1
=====

* `Kyle Lucy`_ reported a bug quickly after the release of 2.2.0 where we broke
  the ``DISABLE_LOGIN`` feature: `#392`_.


2.2.0
=====

* Thanks to `dadosch`_, `Wolfgang Mader`_, and `Tim Brooks`_ this is the first
  version of Paperless that supports Django 2.0!  As a result of their hard
  work, you can now also run Paperless on Python 3.7 as well: `#386`_ &
  `#390`_.
* `Stéphane Brunner`_ added a few lines of code that made tagging interface a
  lot easier on those of us with lots of different tags: `#391`_.
* `Kilian Koeltzsch`_ noticed a bug in how we capture & automatically create
  tags, so that's fixed now too: `#384`_.
* `erikarvstedt`_ tweaked the behaviour of the test suite to be better behaved
  for packaging environments: `#383`_.
* `Lukasz Soluch`_ added CORS support to make building a new Javascript-based
  front-end cleaner & easier: `#387`_.


2.1.0
=====

* `Enno Lohmeier`_ added three simple features that make Paperless a lot more
  user (and developer) friendly:

  1. There's a new search box on the front page: `#374`_.
  2. The correspondents & tags pages now have a column showing the number of
     relevant documents: `#375`_.
  3. The Dockerfile has been tweaked to build faster for those of us who are
     doing active development on Paperless using the Docker environment:
     `#376`_.

* You now also have the ability to customise the interface to your heart's
  content by creating a file called ``overrides.css`` and/or ``overrides.js``
  in the root of your media directory.  Thanks to `Mark McFate`_ for this
  idea: `#371`_


2.0.0
=====

This is a big release as we've changed a core-functionality of Paperless: we no
longer encrypt files with GPG by default.

The reasons for this are many, but it boils down to that the encryption wasn't
really all that useful, as files on-disk were still accessible so long as you
had the key, and the key was most typically stored in the config file.  In
other words, your files are only as safe as the ``paperless`` user is.  In
addition to that, *the contents of the documents were never encrypted*, so
important numbers etc. were always accessible simply by querying the database.
Still, it was better than nothing, but the consensus from users appears to be
that it was more an annoyance than anything else, so this feature is now turned
off unless you explicitly set a passphrase in your config file.

Migrating from 1.x
------------------

Encryption isn't gone, it's just off for new users.  So long as you have
``PAPERLESS_PASSPHRASE`` set in your config or your environment, Paperless
should continue to operate as it always has.  If however, you want to drop
encryption too, you only need to do two things:

1. Run ``./manage.py migrate && ./manage.py change_storage_type gpg unencrypted``.
   This will go through your entire database and Decrypt  All The Things.
2. Remove ``PAPERLESS_PASSPHRASE`` from your ``paperless.conf`` file, or simply
   stop declaring it in your environment.

Special thanks to `erikarvstedt`_, `matthewmoto`_, and `mcronce`_ who did the
bulk of the work on this big change.

1.4.0
=====

* `Quentin Dawans`_ has refactored the document consumer to allow for some
  command-line options.  Notably, you can now direct it to consume from a
  particular ``--directory``, limit the ``--loop-time``, set the time between
  mail server checks with ``--mail-delta`` or just run it as a one-off with
  ``--one-shot``.  See `#305`_ & `#313`_ for more information.
* Refactor the use of travis/tox/pytest/coverage into two files:
  ``.travis.yml`` and ``setup.cfg``.
* Start generating requirements.txt from a Pipfile.  I'll probably switch over
  to just using pipenv in the future.
* All for a alternative FreeBSD-friendly location for ``paperless.conf``.
  Thanks to `Martin Arendtsen`_ who provided this (`#322`_).
* Document consumption events are now logged in the Django admin events log.
  Thanks to `CkuT`_ for doing the legwork on this one and to `Quentin Dawans`_
  & `David Martin`_ for helping to coordinate & work out how the feature would
  be developed.
* `erikarvstedt`_ contributed a pull request (`#328`_) to add ``--noreload``
  to the default server start process.  This helps reduce the load imposed
  by the running webservice.
* Through some discussion on `#253`_ and `#323`_, we've removed a few of the
  hardcoded URL values to make it easier for people to host Paperless on a
  subdirectory.  Thanks to `Quentin Dawans`_ and `Kyle Lucy`_ for helping to
  work this out.
* The clickable area for documents on the listing page has been increased to a
  more predictable space thanks to a glorious hack from `erikarvstedt`_ in
  `#344`_.
* `Strubbl`_ noticed an annoying bug in the bash script wrapping the Docker
  entrypoint and fixed it with some very creating Bash skills: `#352`_.
* You can now use the search field to find documents by tag thanks to
  `thinkjk`_'s *first ever issue*: `#354`_.
* Inotify is now being used to detect additions to the consume directory thanks
  to some excellent work from `erikarvstedt`_ on `#351`_

1.3.0
=====

* You can now run Paperless without a login, though you'll still have to create
  at least one user.  This is thanks to a pull-request from `matthewmoto`_:
  `#295`_.  Note that logins are still required by default, and that you need
  to disable them by setting ``PAPERLESS_DISABLE_LOGIN="true"`` in your
  environment or in ``/etc/paperless.conf``.
* Fix for `#303`_ where sketchily-formatted documents could cause the consumer
  to break and insert half-records into the database breaking all sorts of
  things.  We now capture the return codes of both ``convert`` and ``unpaper``
  and fail-out nicely.
* Fix for additional date types thanks to input from `Isaac`_ and code from
  `BastianPoe`_ (`#301`_).
* Fix for running migrations in the Docker container (`#299`_).  Thanks to
  `Georgi Todorov`_ for the fix (`#300`_) and to `Pit`_ for the review.
* Fix for Docker cases where the issuing user is not UID 1000.  This was a
  collaborative fix between `Jeffrey Portman`_ and `Pit`_ in `#311`_ and
  `#312`_ to fix `#306`_.
* Patch the historical migrations to support MySQL's um, *interesting* way of
  handing indexes (`#308`_).  Thanks to `Simon Taddiken`_ for reporting the
  problem and helping me find where to fix it.

1.2.0
=====

* New Docker image, now based on Alpine, thanks to the efforts of `addadi`_
  and `Pit`_.  This new image is dramatically smaller than the Debian-based
  one, and it also has `a new home on Docker Hub`_.  A proper thank-you to
  `Pit`_ for hosting the image on his Docker account all this time, but after
  some discussion, we decided the image needed a more *official-looking* home.
* `BastianPoe`_ has added the long-awaited feature to automatically skip the
  OCR step when the PDF already contains text. This can be overridden by
  setting ``PAPERLESS_OCR_ALWAYS=YES`` either in your ``paperless.conf`` or
  in the environment.  Note that this also means that Paperless now requires
  ``libpoppler-cpp-dev`` to be installed. **Important**: You'll need to run
  ``pip install -r requirements.txt`` after the usual ``git pull`` to
  properly update.
* `BastianPoe`_ has also contributed a monumental amount of work (`#291`_) to
  solving `#158`_: setting the document creation date based on finding a date
  in the document text.

1.1.0
=====

* Fix for `#283`_, a redirect bug which broke interactions with
  paperless-desktop.  Thanks to `chris-aeviator`_ for reporting it.
* Addition of an optional new financial year filter, courtesy of
  `David Martin`_ `#256`_
* Fixed a typo in how thumbnails were named in exports `#285`_, courtesy of
  `Dan Panzarella`_

1.0.0
=====

* Upgrade to Django 1.11.  **You'll need to run
  ``pip install -r requirements.txt`` after the usual ``git pull`` to
  properly update**.
* Replace the templatetag-based hack we had for document listing in favour of
  a slightly less ugly solution in the form of another template tag with less
  copypasta.
* Support for multi-word-matches for auto-tagging thanks to an excellent
  patch from `ishirav`_ `#277`_.
* Fixed a CSS bug reported by `Stefan Hagen`_ that caused an overlapping of
  the text and checkboxes under some resolutions `#272`_.
* Patched the Docker config to force the serving of static files.  Credit for
  this one goes to `dev-rke`_ via `#248`_.
* Fix file permissions during Docker start up thanks to `Pit`_ on `#268`_.
* Date fields in the admin are now expressed as HTML5 date fields thanks to
  `Lukas Winkler`_'s issue `#278`_

0.8.0
=====

* Paperless can now run in a subdirectory on a host (``/paperless``), rather
  than always running in the root (``/``) thanks to `maphy-psd`_'s work on
  `#255`_.

0.7.0
=====

* **Potentially breaking change**: As per `#235`_, Paperless will no longer
  automatically delete documents attached to correspondents when those
  correspondents are themselves deleted.  This was Django's default
  behaviour, but didn't make much sense in Paperless' case.  Thanks to
  `Thomas Brueggemann`_ and `David Martin`_ for their input on this one.
* Fix for `#232`_ wherein Paperless wasn't recognising ``.tif`` files
  properly.  Thanks to `ayounggun`_ for reporting this one and to
  `Kusti Skytén`_ for posting the correct solution in the Github issue.

0.6.0
=====

* Abandon the shared-secret trick we were using for the POST API in favour
  of BasicAuth or Django session.
* Fix the POST API so it actually works.  `#236`_
* **Breaking change**: We've dropped the use of ``PAPERLESS_SHARED_SECRET``
  as it was being used both for the API (now replaced with a normal auth)
  and form email polling.  Now that we're only using it for email, this
  variable has been renamed to ``PAPERLESS_EMAIL_SECRET``.  The old value
  will still work for a while, but you should change your config if you've
  been using the email polling feature.  Thanks to `Joshua Gilman`_ for all
  the help with this feature.

0.5.0
=====

* Support for fuzzy matching in the auto-tagger & auto-correspondent systems
  thanks to `Jake Gysland`_'s patch `#220`_.
* Modified the Dockerfile to prepare an export directory (`#212`_).  Thanks
  to combined efforts from `Pit`_ and `Strubbl`_ in working out the kinks on
  this one.
* Updated the import/export scripts to include support for thumbnails.  Big
  thanks to `CkuT`_ for finding this shortcoming and doing the work to get
  it fixed in `#224`_.
* All of the following changes are thanks to `David Martin`_:
  * Bumped the dependency on pyocr to 0.4.7 so new users can make use of
  Tesseract 4 if they so prefer (`#226`_).
  * Fixed a number of issues with the automated mail handler (`#227`_, `#228`_)
  * Amended the documentation for better handling of systemd service files (`#229`_)
  * Amended the Django Admin configuration to have nice headers (`#230`_)

0.4.1
=====

* Fix for `#206`_ wherein the pluggable parser didn't recognise files with
  all-caps suffixes like ``.PDF``

0.4.0
=====

* Introducing reminders.  See `#199`_ for more information, but the short
  explanation is that you can now attach simple notes & times to documents
  which are made available via the API.  Currently, the default API
  (basically just the Django admin) doesn't really make use of this, but
  `Thomas Brueggemann`_ over at `Paperless Desktop`_ has said that he would
  like to make use of this feature in his project.

0.3.6
=====

* Fix for `#200`_ (!!) where the API wasn't configured to allow updating the
  correspondent or the tags for a document.
* The ``content`` field is now optional, to allow for the edge case of a
  purely graphical document.
* You can no longer add documents via the admin.  This never worked in the
  first place, so all I've done here is remove the link to the broken form.
* The consumer code has been heavily refactored to support a pluggable
  interface.  Install a paperless consumer via pip and tell paperless about
  it with an environment variable, and you're good to go.  Proper
  documentation is on its way.

0.3.5
=====

* A serious facelift for the documents listing page wherein we drop the
  tabular layout in favour of a tiled interface.
* Users can now configure the number of items per page.
* Fix for `#171`_: Allow users to specify their own ``SECRET_KEY`` value.
* Moved the dotenv loading to the top of settings.py
* Fix for `#112`_: Added checks for binaries required for document
  consumption.

0.3.4
=====

* Removal of django-suit due to a licensing conflict I bumped into in 0.3.3.
  Note that you *can* use Django Suit with Paperless, but only in a
  non-profit situation as their free license prohibits for-profit use.  As a
  result, I can't bundle Suit with Paperless without conflicting with the
  GPL.  Further development will be done against the stock Django admin.
* I shrunk the thumbnails a little 'cause they were too big for me, even on
  my high-DPI monitor.
* BasicAuth support for document and thumbnail downloads, as well as the Push
  API thanks to @thomasbrueggemann.  See `#179`_.

0.3.3
=====

* Thumbnails in the UI and a Django-suit -based face-lift courtesy of @ekw!
* Timezone, items per page, and default language are now all configurable,
  also thanks to @ekw.

0.3.2
=====

* Fix for `#172`_: defaulting ALLOWED_HOSTS to ``["*"]`` and allowing the
  user to set her own value via ``PAPERLESS_ALLOWED_HOSTS`` should the need
  arise.

0.3.1
=====

* Added a default value for ``CONVERT_BINARY``

0.3.0
=====

* Updated to using django-filter 1.x
* Added some system checks so new users aren't confused by misconfigurations.
* Consumer loop time is now configurable for systems with slow writes.  Just
  set ``PAPERLESS_CONSUMER_LOOP_TIME`` to a number of seconds.  The default
  is 10.
* As per `#44`_, we've removed support for ``PAPERLESS_CONVERT``,
  ``PAPERLESS_CONSUME``, and ``PAPERLESS_SECRET``.  Please use
  ``PAPERLESS_CONVERT_BINARY``, ``PAPERLESS_CONSUMPTION_DIR``, and
  ``PAPERLESS_SHARED_SECRET`` respectively instead.

0.2.0
=====

* `#150`_: The media root is now a variable you can set in
  ``paperless.conf``.
* `#148`_: The database location (sqlite) is now a variable you can set in
  ``paperless.conf``.
* `#146`_: Fixed a bug that allowed unauthorised access to the ``/fetch``
  URL.
* `#131`_: Document files are now automatically removed from disk when
  they're deleted in Paperless.
* `#121`_: Fixed a bug where Paperless wasn't setting document creation time
  based on the file naming scheme.
* `#81`_: Added a hook to run an arbitrary script after every document is
  consumed.
* `#98`_: Added optional environment variables for ImageMagick so that it
  doesn't explode when handling Very Large Documents or when it's just
  running on a low-memory system.  Thanks to `Florian Harr`_ for his help on
  this one.
* `#89`_ Ported the auto-tagging code to correspondents as well.  Thanks to
  `Justin Snyman`_ for the pointers in the issue queue.
* Added support for guessing the date from the file name along with the
  correspondent, title, and tags.  Thanks to `Tikitu de Jager`_ for his pull
  request that I took forever to merge and to `Pit`_ for his efforts on the
  regex front.
* `#94`_: Restored support for changing the created date in the UI.  Thanks
  to `Martin Honermeyer`_ and `Tim White`_ for working with me on this.

0.1.1
=====

* Potentially **Breaking Change**: All references to "sender" in the code
  have been renamed to "correspondent" to better reflect the nature of the
  property (one could quite reasonably scan a document before sending it to
  someone.)
* `#67`_: Rewrote the document exporter and added a new importer that allows
  for full metadata retention without depending on the file name and
  modification time.  A big thanks to `Tikitu de Jager`_, `Pit`_,
  `Florian Jung`_, and `Christopher Luu`_ for their code snippets and
  contributing conversation that lead to this change.
* `#20`_: Added *unpaper* support to help in cleaning up the scanned image
  before it's OCR'd.  Thanks to `Pit`_ for this one.
* `#71`_ Added (encrypted) thumbnails in anticipation of a proper UI.
* `#68`_: Added support for using a proper config file at
  ``/etc/paperless.conf`` and modified the systemd unit files to use it.
* Refactored the Vagrant installation process to use environment variables
  rather than asking the user to modify ``settings.py``.
* `#44`_: Harmonise environment variable names with constant names.
* `#60`_: Setup logging to actually use the Python native logging framework.
* `#53`_: Fixed an annoying bug that caused ``.jpeg`` and ``.JPG`` images
  to be imported but made unavailable.

0.1.0
=====

* Docker support!  Big thanks to `Wayne Werner`_, `Brian Conn`_, and
  `Tikitu de Jager`_ for this one, and especially to `Pit`_
  who spearheadded this effort.
* A simple REST API is in place, but it should be considered unstable.
* Cleaned up the consumer to use temporary directories instead of a single
  scratch space.  (Thanks `Pit`_)
* Improved the efficiency of the consumer by parsing pages more intelligently
  and introducing a threaded OCR process (thanks again `Pit`_).
* `#45`_: Cleaned up the logic for tag matching.  Reported by `darkmatter`_.
* `#47`_: Auto-rotate landscape documents.  Reported by `Paul`_ and fixed by
  `Pit`_.
* `#48`_: Matching algorithms should do so on a word boundary (`darkmatter`_)
* `#54`_: Documented the re-tagger (`zedster`_)
* `#57`_: Make sure file is preserved on import failure (`darkmatter`_)
* Added tox with pep8 checking

0.0.6
=====

* Added support for parallel OCR (significant work from `Pit`_)
* Sped up the language detection (significant work from `Pit`_)
* Added simple logging

0.0.5
=====

* Added support for image files as documents (png, jpg, gif, tiff)
* Added a crude means of HTTP POST for document imports
* Added IMAP mail support
* Added a re-tagging utility
* Documentation for the above as well as data migration

0.0.4
=====

* Added automated tagging basted on keyword matching
* Cleaned up the document listing page
* Removed ``User`` and ``Group`` from the admin
* Added ``pytz`` to the list of requirements

0.0.3
=====

* Added basic tagging

0.0.2
=====

* Added language detection
* Added datestamps to ``document_exporter``.
* Changed ``settings.TESSERACT_LANGUAGE`` to ``settings.OCR_LANGUAGE``.

0.0.1
=====

* Initial release

.. _Brian Conn: https://github.com/TheConnMan
.. _Christopher Luu: https://github.com/nuudles
.. _Florian Jung: https://github.com/the01
.. _Tikitu de Jager: https://github.com/tikitu
.. _Paul: https://github.com/polo2ro
.. _Pit: https://github.com/pitkley
.. _Wayne Werner: https://github.com/waynew
.. _darkmatter: https://github.com/darkmatter
.. _zedster: https://github.com/zedster
.. _Martin Honermeyer: https://github.com/djmaze
.. _Tim White: https://github.com/timwhite
.. _Florian Harr: https://github.com/evils
.. _Justin Snyman: https://github.com/stringlytyped
.. _Thomas Brueggemann: https://github.com/thomasbrueggemann
.. _Jake Gysland: https://github.com/jgysland
.. _Strubbl: https://github.com/strubbl
.. _CkuT: https://github.com/CkuT
.. _David Martin: https://github.com/ddddavidmartin
.. _Paperless Desktop: https://github.com/thomasbrueggemann/paperless-desktop
.. _Joshua Gilman: https://github.com/jmgilman
.. _ayounggun: https://github.com/ayounggun
.. _Kusti Skytén: https://github.com/kskyten
.. _maphy-psd: https://github.com/maphy-psd
.. _ishirav: https://github.com/ishirav
.. _Stefan Hagen: https://github.com/xkpd3
.. _dev-rke: https://github.com/dev-rke
.. _Lukas Winkler: https://github.com/Findus23
.. _chris-aeviator: https://github.com/chris-aeviator
.. _Dan Panzarella: https://github.com/pzl
.. _addadi: https://github.com/addadi
.. _BastianPoe: https://github.com/BastianPoe
.. _matthewmoto: https://github.com/matthewmoto
.. _Isaac: https://github.com/isaacsando
.. _Georgi Todorov: https://github.com/TeraHz
.. _Jeffrey Portman: https://github.com/ChromoX
.. _Simon Taddiken: https://github.com/skuzzle
.. _Quentin Dawans: https://github.com/ovv
.. _Martin Arendtsen: https://github.com/Arendtsen
.. _erikarvstedt: https://github.com/erikarvstedt
.. _Kyle Lucy: https://github.com/kmlucy
.. _thinkjk: https://github.com/thinkjk
.. _mcronce: https://github.com/mcronce
.. _Enno Lohmeier: https://github.com/elohmeier
.. _Mark McFate: https://github.com/SummittDweller
.. _dadosch: https://github.com/dadosch
.. _Wolfgang Mader: https://github.com/wmader
.. _Tim Brooks: https://github.com/brookst
.. _Stéphane Brunner: https://github.com/sbrunner
.. _Kilian Koeltzsch: https://github.com/kiliankoe
.. _Lukasz Soluch: https://github.com/LukaszSolo
.. _Joshua Taillon: https://github.com/jat255
.. _dubit0: https://github.com/dubit0
.. _ahyear: https://github.com/ahyear
.. _jonaswinkler: https://github.com/jonaswinkler
.. _thepill: https://github.com/thepill
.. _Andrew Peng: https://github.com/pengc99
.. _euri10: https://github.com/euri10
.. _Ulli: https://github.com/Ulli2k
.. _tsia: https://github.com/tsia
.. _Sblop: https://github.com/Sblop
.. _Colin Frei: https://github.com/colinfrei
.. _khrise: https://github.com/khrise
.. _syntonym: https://github.com/syntonym
.. _JOKer: https://github.com/MasterofJOKers
.. _Brian Cribbs: https://github.com/cribbstechnolog
.. _Brendan M. Sleight: https://github.com/bmsleight

.. _#20: https://github.com/the-paperless-project/paperless/issues/20
.. _#44: https://github.com/the-paperless-project/paperless/issues/44
.. _#45: https://github.com/the-paperless-project/paperless/issues/45
.. _#47: https://github.com/the-paperless-project/paperless/issues/47
.. _#48: https://github.com/the-paperless-project/paperless/issues/48
.. _#53: https://github.com/the-paperless-project/paperless/issues/53
.. _#54: https://github.com/the-paperless-project/paperless/issues/54
.. _#57: https://github.com/the-paperless-project/paperless/issues/57
.. _#60: https://github.com/the-paperless-project/paperless/issues/60
.. _#67: https://github.com/the-paperless-project/paperless/issues/67
.. _#68: https://github.com/the-paperless-project/paperless/issues/68
.. _#71: https://github.com/the-paperless-project/paperless/issues/71
.. _#81: https://github.com/the-paperless-project/paperless/issues/81
.. _#89: https://github.com/the-paperless-project/paperless/issues/89
.. _#94: https://github.com/the-paperless-project/paperless/issues/94
.. _#98: https://github.com/the-paperless-project/paperless/issues/98
.. _#112: https://github.com/the-paperless-project/paperless/issues/112
.. _#121: https://github.com/the-paperless-project/paperless/issues/121
.. _#131: https://github.com/the-paperless-project/paperless/issues/131
.. _#146: https://github.com/the-paperless-project/paperless/issues/146
.. _#148: https://github.com/the-paperless-project/paperless/pull/148
.. _#150: https://github.com/the-paperless-project/paperless/pull/150
.. _#158: https://github.com/the-paperless-project/paperless/issues/158
.. _#171: https://github.com/the-paperless-project/paperless/issues/171
.. _#172: https://github.com/the-paperless-project/paperless/issues/172
.. _#179: https://github.com/the-paperless-project/paperless/pull/179
.. _#199: https://github.com/the-paperless-project/paperless/issues/199
.. _#200: https://github.com/the-paperless-project/paperless/issues/200
.. _#206: https://github.com/the-paperless-project/paperless/issues/206
.. _#212: https://github.com/the-paperless-project/paperless/pull/212
.. _#220: https://github.com/the-paperless-project/paperless/pull/220
.. _#224: https://github.com/the-paperless-project/paperless/pull/224
.. _#226: https://github.com/the-paperless-project/paperless/pull/226
.. _#227: https://github.com/the-paperless-project/paperless/pull/227
.. _#228: https://github.com/the-paperless-project/paperless/pull/228
.. _#229: https://github.com/the-paperless-project/paperless/pull/229
.. _#230: https://github.com/the-paperless-project/paperless/pull/230
.. _#232: https://github.com/the-paperless-project/paperless/issues/232
.. _#235: https://github.com/the-paperless-project/paperless/issues/235
.. _#236: https://github.com/the-paperless-project/paperless/issues/236
.. _#255: https://github.com/the-paperless-project/paperless/pull/255
.. _#268: https://github.com/the-paperless-project/paperless/pull/268
.. _#277: https://github.com/the-paperless-project/paperless/pull/277
.. _#272: https://github.com/the-paperless-project/paperless/issues/272
.. _#248: https://github.com/the-paperless-project/paperless/issues/248
.. _#278: https://github.com/the-paperless-project/paperless/issues/248
.. _#283: https://github.com/the-paperless-project/paperless/issues/283
.. _#256: https://github.com/the-paperless-project/paperless/pull/256
.. _#285: https://github.com/the-paperless-project/paperless/pull/285
.. _#291: https://github.com/the-paperless-project/paperless/pull/291
.. _#295: https://github.com/the-paperless-project/paperless/pull/295
.. _#299: https://github.com/the-paperless-project/paperless/issues/299
.. _#300: https://github.com/the-paperless-project/paperless/pull/300
.. _#301: https://github.com/the-paperless-project/paperless/issues/301
.. _#303: https://github.com/the-paperless-project/paperless/issues/303
.. _#305: https://github.com/the-paperless-project/paperless/issues/305
.. _#306: https://github.com/the-paperless-project/paperless/issues/306
.. _#308: https://github.com/the-paperless-project/paperless/issues/308
.. _#311: https://github.com/the-paperless-project/paperless/pull/311
.. _#312: https://github.com/the-paperless-project/paperless/pull/312
.. _#313: https://github.com/the-paperless-project/paperless/pull/313
.. _#322: https://github.com/the-paperless-project/paperless/pull/322
.. _#328: https://github.com/the-paperless-project/paperless/pull/328
.. _#253: https://github.com/the-paperless-project/paperless/issues/253
.. _#262: https://github.com/the-paperless-project/paperless/issues/262
.. _#323: https://github.com/the-paperless-project/paperless/issues/323
.. _#344: https://github.com/the-paperless-project/paperless/pull/344
.. _#351: https://github.com/the-paperless-project/paperless/pull/351
.. _#352: https://github.com/the-paperless-project/paperless/pull/352
.. _#354: https://github.com/the-paperless-project/paperless/issues/354
.. _#371: https://github.com/the-paperless-project/paperless/issues/371
.. _#374: https://github.com/the-paperless-project/paperless/pull/374
.. _#375: https://github.com/the-paperless-project/paperless/pull/375
.. _#376: https://github.com/the-paperless-project/paperless/pull/376
.. _#383: https://github.com/the-paperless-project/paperless/pull/383
.. _#384: https://github.com/the-paperless-project/paperless/issues/384
.. _#386: https://github.com/the-paperless-project/paperless/issues/386
.. _#387: https://github.com/the-paperless-project/paperless/pull/387
.. _#391: https://github.com/the-paperless-project/paperless/pull/391
.. _#390: https://github.com/the-paperless-project/paperless/pull/390
.. _#392: https://github.com/the-paperless-project/paperless/issues/392
.. _#393: https://github.com/the-paperless-project/paperless/issues/393
.. _#395: https://github.com/the-paperless-project/paperless/pull/395
.. _#394: https://github.com/the-paperless-project/paperless/issues/394
.. _#396: https://github.com/the-paperless-project/paperless/pull/396
.. _#399: https://github.com/the-paperless-project/paperless/pull/399
.. _#400: https://github.com/the-paperless-project/paperless/pull/400
.. _#401: https://github.com/the-paperless-project/paperless/pull/401
.. _#405: https://github.com/the-paperless-project/paperless/pull/405
.. _#406: https://github.com/the-paperless-project/paperless/issues/406
.. _#412: https://github.com/the-paperless-project/paperless/issues/412
.. _#413: https://github.com/the-paperless-project/paperless/pull/413
.. _#414: https://github.com/the-paperless-project/paperless/issues/414
.. _#423: https://github.com/the-paperless-project/paperless/issues/423
.. _#433: https://github.com/the-paperless-project/paperless/issues/433
.. _#440: https://github.com/the-paperless-project/paperless/pull/440
.. _#441: https://github.com/the-paperless-project/paperless/pull/441
.. _#442: https://github.com/the-paperless-project/paperless/pull/442
.. _#466: https://github.com/the-paperless-project/paperless/pull/466
.. _#471: https://github.com/the-paperless-project/paperless/pull/471
.. _#475: https://github.com/the-paperless-project/paperless/pull/475
.. _#481: https://github.com/the-paperless-project/paperless/pull/481
.. _#483: https://github.com/the-paperless-project/paperless/pull/483
.. _#484: https://github.com/the-paperless-project/paperless/pull/484
.. _#488: https://github.com/the-paperless-project/paperless/pull/488
.. _#489: https://github.com/the-paperless-project/paperless/pull/489
.. _#492: https://github.com/the-paperless-project/paperless/pull/492

.. _pipenv: https://docs.pipenv.org/
.. _a new home on Docker Hub: https://hub.docker.com/r/danielquinn/paperless/
.. _optipng: http://optipng.sourceforge.net/


================================================
FILE: docs/conf.py
================================================
# -*- coding: utf-8 -*-
#
# Paperless documentation build configuration file, created by
# sphinx-quickstart on Mon Oct 26 18:36:52 2015.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys
import os

__version__ = None
exec(open("../src/paperless/version.py").read())


# Believe it or not, this is the officially sanctioned way to add custom CSS.
def setup(app):
    app.add_stylesheet("custom.css")

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))

# -- General configuration ------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
    'sphinx.ext.autodoc',
    'sphinx.ext.intersphinx',
    'sphinx.ext.todo',
    'sphinx.ext.imgmath',
    'sphinx.ext.viewcode',
]

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

# The suffix of source filenames.
source_suffix = '.rst'

# The encoding of source files.
#source_encoding = 'utf-8-sig'

# The master toctree document.
master_doc = 'index'

# General information about the project.
project = u'Paperless'
copyright = u'2015, Daniel Quinn'

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#

#
# If the build process ever explodes here, it's because you've set the version
# number in paperless.version to a tuple with 3 numbers in it.
#

# The short X.Y version.
version = ".".join([str(_) for _ in __version__[:2]])
# The full version, including alpha/beta/rc tags.
release = ".".join([str(_) for _ in __version__[:3]])

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None

# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']

# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None

# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True

# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True

# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'

# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []

# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False


# -- Options for HTML output ----------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
html_theme = 'default'

# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}

# Add any paths that contain custom themes here, relative to this directory.
html_theme_path = []

# The name for this set of Sphinx documents.  If None, it defaults to
# "<project> v<release> documentation".
#html_title = None

# A shorter title for the navigation bar.  Default is the same as html_title.
#html_short_title = None

# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None

# The name of an image file (within the static path) to use as favicon of the
# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []

# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'

# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True

# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}

# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}

# If false, no module index is generated.
#html_domain_indices = True

# If false, no index is generated.
#html_use_index = True

# If true, the index is split into individual pages for each letter.
#html_split_index = False

# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True

# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True

# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True

# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it.  The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''

# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None

# Output file base name for HTML help builder.
htmlhelp_basename = 'paperless'


#
# Attempt to use the ReadTheDocs theme.  If it's not installed, fallback to
# the default.
#

try:
    import sphinx_rtd_theme
    html_theme = "sphinx_rtd_theme"
    html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
except ImportError:
    pass

# -- Options for LaTeX output ---------------------------------------------

latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',

# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',

# Additional stuff for the LaTeX preamble.
#'preamble': '',
}

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
#  author, documentclass [howto, manual, or own class]).
latex_documents = [
  ('index', 'paperless.tex', u'Paperless Documentation',
   u'Daniel Quinn', 'manual'),
]

# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None

# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False

# If true, show page references after internal links.
#latex_show_pagerefs = False

# If true, show URL addresses after external links.
#latex_show_urls = False

# Documents to append as an appendix to all manuals.
#latex_appendices = []

# If false, no module index is generated.
#latex_domain_indices = True


# -- Options for manual page output ---------------------------------------

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
    ('index', 'paperless', u'Paperless Documentation',
     [u'Daniel Quinn'], 1)
]

# If true, show URL addresses after external links.
#man_show_urls = False


# -- Options for Texinfo output -------------------------------------------

# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
#  dir menu entry, description, category)
texinfo_documents = [
  ('index', 'Paperless', u'Paperless Documentation',
   u'Daniel Quinn', 'paperless', 'Scan, index, and archive all of your paper documents.',
   'Miscellaneous'),
]

# Documents to append as an appendix to all manuals.
#texinfo_appendices = []

# If false, no module index is generated.
#texinfo_domain_indices = True

# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'

# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False


# -- Options for Epub output ----------------------------------------------

# Bibliographic Dublin Core info.
epub_title = u'Paperless'
epub_author = u'Daniel Quinn'
epub_publisher = u'Daniel Quinn'
epub_copyright = u'2015, Daniel Quinn'

# The basename for the epub file. It defaults to the project name.
#epub_basename = u'Paperless'

# The HTML theme for the epub output. Since the default themes are not optimized
# for small screen space, using the same theme for HTML and epub output is
# usually not wise. This defaults to 'epub', a theme designed to save visual
# space.
#epub_theme = 'epub'

# The language of the text. It defaults to the language option
# or en if the language is not set.
#epub_language = ''

# The scheme of the identifier. Typical schemes are ISBN or URL.
#epub_scheme = ''

# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#epub_identifier = ''

# A unique identification for the text.
#epub_uid = ''

# A tuple containing the cover image and cover page html template filenames.
#epub_cover = ()

# A sequence of (type, uri, title) tuples for the guide element of content.opf.
#epub_guide = ()

# HTML files that should be inserted before the pages created by sphinx.
# The format is a list of tuples containing the path and title.
#epub_pre_files = []

# HTML files shat should be inserted after the pages created by sphinx.
# The format is a list of tuples containing the path and title.
#epub_post_files = []

# A list of files that should not be packed into the epub file.
epub_exclude_files = ['search.html']

# The depth of the table of contents in toc.ncx.
#epub_tocdepth = 3

# Allow duplicate toc entries.
#epub_tocdup = True

# Choose between 'default' and 'includehidden'.
#epub_tocscope = 'default'

# Fix unsupported image types using the PIL.
#epub_fix_images = False

# Scale large images.
#epub_max_image_width = 0

# How to display URL addresses: 'footnote', 'no', or 'inline'.
#epub_show_urls = 'inline'

# If false, no index is generated.
#epub_use_index = True


# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'http://docs.python.org/': None}


================================================
FILE: docs/consumption.rst
================================================
.. _consumption:

Consumption
###########

Once you've got Paperless setup, you need to start feeding documents into it.
Currently, there are three options: the consumption directory, IMAP (email), and
HTTP POST.


.. _consumption-directory:

The Consumption Directory
=========================

The primary method of getting documents into your database is by putting them in
the consumption directory.  The ``document_consumer`` script runs in an infinite
loop looking for new additions to this directory and when it finds them, it goes
about the process of parsing them with the OCR, indexing what it finds, and
encrypting the PDF (if ``PAPERLESS_PASSPHRASE`` is set), storing it in the
media directory.

Getting stuff into this directory is up to you.  If you're running Paperless
on your local computer, you might just want to drag and drop files there, but if
you're running this on a server and want your scanner to automatically push
files to this directory, you'll need to setup some sort of service to accept the
files from the scanner.  Typically, you're looking at an FTP server like
`Proftpd`_ or `Samba`_.

.. _Proftpd: http://www.proftpd.org/
.. _Samba: http://www.samba.org/

So where is this consumption directory?  It's wherever you define it.  Look for
the ``CONSUMPTION_DIR`` value in ``settings.py``.  Set that to somewhere
appropriate for your use and put some documents in there.  When you're ready,
follow the :ref:`consumer <utilities-consumer>` instructions to get it running.


.. _consumption-directory-hook:

Hooking into the Consumption Process
------------------------------------

Sometimes you may want to do something arbitrary whenever a document is
consumed.  Rather than try to predict what you may want to do, Paperless lets
you execute scripts of your own choosing just before or after a document is
consumed using a couple simple hooks.

Just write a script, put it somewhere that Paperless can read & execute, and
then put the path to that script in ``paperless.conf`` with the variable name
of either ``PAPERLESS_PRE_CONSUME_SCRIPT`` or
``PAPERLESS_POST_CONSUME_SCRIPT``.  The script will be executed before or
or after the document is consumed respectively.

.. important::

    These scripts are executed in a **blocking** process, which means that if
    a script takes a long time to run, it can significantly slow down your
    document consumption flow.  If you want things to run asynchronously,
    you'll have to fork the process in your script and exit.


.. _consumption-directory-hook-variables:

What Can These Scripts Do?
..........................

It's your script, so you're only limited by your imagination and the laws of
physics.  However, the following values are passed to the scripts in order:


.. _consumption-director-hook-variables-pre:

Pre-consumption script
::::::::::::::::::::::

* Document file name

A simple but common example for this would be creating a simple script like
this:

``/usr/local/bin/ocr-pdf``

.. code:: bash

    #!/usr/bin/env bash
    pdf2pdfocr.py -i ${1}

``/etc/paperless.conf``

.. code:: bash

    ...
    PAPERLESS_PRE_CONSUME_SCRIPT="/usr/local/bin/ocr-pdf"
    ...

This will pass the path to the document about to be consumed to ``/usr/local/bin/ocr-pdf``,
which will in turn call `pdf2pdfocr.py`_ on your document, which will then
overwrite the file with an OCR'd version of the file and exit.  At which point,
the consumption process will begin with the newly modified file.

.. _pdf2pdfocr.py: https://github.com/LeoFCardoso/pdf2pdfocr


.. _consumption-director-hook-variables-post:

Post-consumption script
:::::::::::::::::::::::

* Document id
* Generated file name
* Source path
* Thumbnail path
* Download URL
* Thumbnail URL
* Correspondent
* Tags

The script can be in any language you like, but for a simple shell script
example, you can take a look at ``post-consumption-example.sh`` in the
``scripts`` directory in this project.


.. _consumption-imap:

IMAP (Email)
============

Another handy way to get documents into your database is to email them to
yourself.  The typical use-case would be to be out for lunch and want to send a
copy of the receipt back to your system at home.  Paperless can be taught to
pull emails down from an arbitrary account and dump them into the consumption
directory where the process :ref:`above <consumption-directory>` will follow the
usual pattern on consuming the document.

Some things you need to know about this feature:

* It's disabled by default.  By setting the values below it will be enabled.
* It's been tested in a limited environment, so it may not work for you (please
  submit a pull request if you can!)
* It's designed to **delete mail from the server once consumed**.  So don't go
  pointing this to your personal email account and wonder where all your stuff
  went.
* Currently, only one photo (attachment) per email will work.

So, with all that in mind, here's what you do to get it running:

1. Setup a new email account somewhere, or if you're feeling daring, create a
   folder in an existing email box and note the path to that folder.
2. In ``/etc/paperless.conf`` set all of the appropriate values in
   ``PATHS AND FOLDERS`` and ``SECURITY``.
   If you decided to use a subfolder of an existing account, then make sure you
   set ``PAPERLESS_CONSUME_MAIL_INBOX`` accordingly here.  You also have to set
   the ``PAPERLESS_EMAIL_SECRET`` to something you can remember 'cause you'll
   have to include that in every email you send.
3. Restart the :ref:`consumer <utilities-consumer>`.  The consumer will check
   the configured email account at startup and from then on every 10 minutes
   for something new and pulls down whatever it finds.
4. Send yourself an email!  Note that the subject is treated as the file name,
   so if you set the subject to ``Correspondent - Title - tag,tag,tag``, you'll
   get what you expect.  Also, you must include the aforementioned secret
   string in every email so the fetcher knows that it's safe to import.
   Note that Paperless only allows the email title to consist of safe characters
   to be imported. These consist of alpha-numeric characters and ``-_ ,.'``.
5. After a few minutes, the consumer will poll your mailbox, pull down the
   message, and place the attachment in the consumption directory with the
   appropriate name.  A few minutes later, the consumer will import it like any
   other file.


.. _consumption-http:

HTTP POST
=========

You can also submit a document via HTTP POST, so long as you do so after
authenticating.  To push your document to Paperless, send an HTTP POST to the
server with the following name/value pairs:

* ``correspondent``: The name of the document's correspondent.  Note that there
  are restrictions on what characters you can use here.  Specifically,
  alphanumeric characters, `-`, `,`, `.`, and `'` are ok, everything else is
  out.  You also can't use the sequence ` - ` (space, dash, space).
* ``title``: The title of the document.  The rules for characters is the same
  here as the correspondent.
* ``document``: The file you're uploading

Specify ``enctype="multipart/form-data"``, and then POST your file with::

    Content-Disposition: form-data; name="document"; filename="whatever.pdf"

An example of this in HTML is a typical form:

.. code:: html

    <form method="post" enctype="multipart/form-data">
        <input type="text" name="correspondent" value="My Correspondent" />
        <input type="text" name="title" value="My Title" />
        <input type="file" name="document" />
        <input type="submit" name="go" value="Do the thing" />
    </form>

But a potentially more useful way to do this would be in Python.  Here we use
the requests library to handle basic authentication and to send the POST data
to the URL.

.. code:: python

    import os

    from hashlib import sha256

    import requests
    from requests.auth import HTTPBasicAuth

    # You authenticate via BasicAuth or with a session id.
    # We use BasicAuth here
    username = "my-username"
    password = "my-super-secret-password"

    # Where you have Paperless installed and listening
    url = "http://localhost:8000/push"

    # Document metadata
    correspondent = "Test Correspondent"
    title = "Test Title"

    # The local file you want to push
    path = "/path/to/some/directory/my-document.pdf"


    with open(path, "rb") as f:

        response = requests.post(
            url=url,
            data={"title": title,  "correspondent": correspondent},
            files={"document": (os.path.basename(path), f, "application/pdf")},
            auth=HTTPBasicAuth(username, password),
            allow_redirects=False
        )

        if response.status_code == 202:

            # Everything worked out ok
            print("Upload successful")

        else:

            # If you don't get a 202, it's probably because your credentials
            # are wrong or something.  This will give you a rough idea of what
            # happened.

            print("We got HTTP status code: {}".format(response.status_code))
            for k, v in response.headers.items():
                print("{}: {}".format(k, v))


================================================
FILE: docs/contributing.rst
================================================
.. _contributing:

Contributing to Paperless
#########################

Maybe you've been using Paperless for a while and want to add a feature or two,
or maybe you've come across a bug that you have some ideas how to solve.  The
beauty of Free software is that you can see what's wrong and help to get it
fixed for everyone!


How to Get Your Changes Rolled Into Paperless
=============================================

If you've found a bug, but don't know how to fix it, you can always post an
issue on `GitHub`_ in the hopes that someone will have the time to fix it for
you.  If however you're the one with the time, pull requests are always
welcome, you just have to make sure that your code conforms to a few standards:

Pep8
----

It's the standard for all Python development, so it's `very well documented`_.
The short version is:

* Lines should wrap at 79 characters
* Use ``snake_case`` for variables, ``CamelCase`` for classes, and ``ALL_CAPS``
  for constants.
* Space out your operators: ``stuff + 7`` instead of ``stuff+7``
* Two empty lines between classes, and functions, but 1 empty line between
  class methods.

There's more to it than that, but if you follow those, you'll probably be
alright.  When you submit your pull request, there's a pep8 checker that'll
look at your code to see if anything is off.  If it finds anything, it'll
complain at you until you fix it.


Additional Style Guides
-----------------------

Where pep8 is ambiguous, I've tried to be a little more specific.  These rules
aren't hard-and-fast, but if you can conform to them, I'll appreciate it and
spend less time trying to conform your PR before merging:


Function calls
..............

If you're calling a function and that necessitates more than one line of code,
please format it like this:

.. code:: python

    my_function(
        argument1,
        kwarg1="x",
        kwarg2="y"
        another_really_long_kwarg="some big value"
        a_kwarg_calling_another_long_function=another_function(
            another_arg,
            another_kwarg="kwarg!"
        )
    )

This is all in the interest of code uniformity rather than anything else.  If
we stick to a style, everything is understandable in the same way.


Quoting Strings
...............

pep8 is a little too open-minded on this for my liking.  Python strings should
be quoted with double quotes (``"``) except in cases where the resulting string
would require too much escaping of a double quote, in which case, a single
quoted, or triple-quoted string will do:

.. code:: python

    my_string = "This is my string"
    problematic_string = 'This is a "string" with "quotes" in it'

In HTML templates, please use double-quotes for tag attributes, and single
quotes for arguments passed to Django tempalte tags:

.. code:: html

    <div class="stuff">
        <a href="{% url 'some-url-name' pk='w00t' %}">link this</a>
    </div>

This is to keep linters happy they look at an HTML file and see an attribute
closing the ``"`` before it should have been.

--

That's all there is in terms of guidelines, so I hope it's not too daunting.


Indentation & Spacing
.....................

When it comes to indentation:

* For Python, the rule is: follow pep8 and use 4 spaces.
* For Javascript, CSS, and HTML, please use 1 tab.

Additionally, Django templates making use of block elements like ``{% if %}``,
``{% for %}``, and ``{% block %}`` etc. should be indented:

Good:

.. code:: html

    {% block stuff %}
    	<h1>This is the stuff</h1>
    {% endblock %}

Bad:

.. code:: html

    {% block stuff %}
    <h1>This is the stuff</h1>
    {% endblock %}


The Code of Conduct
===================

Paperless has a `code of conduct`_.  It's a lot like the other ones you see out
there, with a few small changes, but basically it boils down to:

> Don't be an ass, or you might get banned.

I'm proud to say that the CoC has never had to be enforced because everyone has
been awesome, friendly, and professional.

.. _GitHub: https://github.com/the-paperless-project/paperless/issues
.. _very well documented: https://www.python.org/dev/peps/pep-0008/
.. _code of conduct: https://github.com/the-paperless-project/paperless/blob/master/CODE_OF_CONDUCT.md


================================================
FILE: docs/customising.rst
================================================
.. _customising:

Customising Paperless
#####################

Currently, the Paperless' interface is just the default Django admin, which
while powerful, is rather boring.  If you'd like to give the site a bit of a
face-lift, or if you simply want to adjust the colours, contrast, or font size
to make things easier to read, you can do that by adding your own CSS or
Javascript quite easily.


.. _customising-overrides:

Overrides
=========

On every page load, Paperless looks for two files in your media root directory
(the directory defined by your ``PAPERLESS_MEDIADIR`` configuration variable or
the default, ``<project root>/media/``) for two files:

* ``overrides.css``
* ``overrides.js``

If it finds either or both of those files, they'll be loaded into the page: the
CSS in the ``<head>``, and the Javascript stuffed into the last line of the
``<body>``.


.. _customising-overrides-note:

An important note about customisation
-------------------------------------

Any changes you make to the site with your CSS or Javascript are likely to
depend on the structure of the current HTML and/or the existing CSS rules.  For
the most part it's safe to assume that these bits won't change, but *sometimes
they do* as features are added or bugs are fixed.

If you make a change that you think others would appreciate though, submit it
as a pull request and maybe we can find a way to work it into the project by
default!

================================================
FILE: docs/examples/lxc/lxc-install.sh
================================================
#!/usr/bin/env bash

# Bash script to install paperless in lxc containter
# paperless.lan
#
# Will set-up paperless, apache2 and proftpd
#
# lxc launch ubuntu: paperless
# lxc exec paperless -- sh -c "sudo apt-get update && sudo apt-get install -y wget"
# lxc exec paperless -- sh -c "wget https://raw.githubusercontent.com/the-paperless-project/paperless/master/docs/examples/lxc/lxc-install.sh && /bin/bash lxc-install.sh --email "
#
#
set +e
PASSWORD=$(< /dev/urandom tr -dc _A-Z-a-z-0-9+@%^{} | head -c20;echo;)
EMAIL=

function displayHelp() {
    echo "available parameters:
    -e <email> | --email <email> 
    -p <password> | --password <password>
    "
}

POSITIONAL=()
while [[ $# -gt 0 ]]
do
key="$1"
i=$key

case $i in
    -e|--email)
      EMAIL="${2}"
      shift
      shift
    ;;
    -p|--password)
      PASSWORD="${2}"
      shift
      shift
    ;;
    --default|-h|--help)
      shift
      displayHelp
      exit 0
    ;;
    *)
      echo "argument: $i not recognized"
      exit 2
    ;;
esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters

if [ -z $EMAIL ]; then
  echo "missing email, try running with -h "
  exit 3
fi
if [[ $(/usr/bin/id -u) -ne 0 ]]; then
    echo "Not running as root"
    exit
fi

if [ $(grep -c paperless /etc/passwd) -eq 0 ]; then
  # Add paperless user with no password
  adduser --disabled-password --gecos "" paperless
fi

if [ $(grep -c ftpupload /etc/passwd) -eq 0 ]; then
  # Add ftpupload
  adduser --disabled-password --gecos "" ftpupload
  echo "Set ftpupload password: "
  #passwd ftpupload
  #TODO: generate some password and allow parameter 
  echo "ftpupload:ftpuploadpassword" | chpasswd
fi

if [ $(id -nG paperless | grep -Fcw ftpupload) -eq 0 ]; then
  # Allow paperless group to access
  adduser paperless ftpupload
  chmod g+w /home/ftpupload 
fi

# Get apt up to date
apt-get update

# Needed for plain Paperless
apt-get -y install unpaper gnupg libpoppler-cpp-dev python3-pyocr tesseract-ocr imagemagick optipng git

# Needed for Apache
apt-get -y install apache2 libapache2-mod-wsgi-py3

if [ ! -f /etc/proftpd/proftpd.conf ]; then
  # Install ftp server and make sure all uplaoded files are owned by paperless
  apt-get -y install proftpd
fi
if [ $(grep -c paperless /etc/proftpd/proftpd.conf) -eq 0 ]; then
  cat <<EOF >> /etc/proftpd/proftpd.conf
  <Directory /home/ftpupload/>
    UserOwner   paperless
    GroupOwner  paperless
  </Directory>
EOF
  systemctl restart proftpd
fi

#Get Paperless from git 
su -c "cd /home/paperless ; git clone https://github.com/the-paperless-project/paperless" paperless

# Install Pip Requirements
apt-get -y install python3-pip python3-venv libpq-dev
cd /home/paperless/paperless
pip3 install -r requirements.txt

# Take paperless.conf.example and set consumuption dir (ftp dir)
sed  -e '/PAPERLESS_CONSUMPTION_DIR=/s/=.*/=\"\/home\/ftpupload\/\"/' \
     /home/paperless/paperless/paperless.conf.example  >/etc/paperless.conf

# Update /etc/paperless.conf with PAPERLESS_SECRET_KEY
SECRET=$(strings /dev/urandom | grep -o '[[:alnum:]]' | head -n 30 | tr -d '\n'; echo)
sed  -i "s/#PAPERLESS_SECRET_KEY.*/PAPERLESS_SECRET_KEY=$SECRET/" /etc/paperless.conf 

#Initialise the SQLite database 
su -c "cd /home/paperless/paperless/src/ ; ./manage.py migrate" paperless
echo "if superuser doesn't exists, create one with login: paperless and password: ${PASSWORD}"
#Create a user for your Paperless instance
su -c "cd /home/paperless/paperless/src/ ; echo ./manage.py create_superuser_with_password --username paperless --email ${EMAIL} --password ${PASSWORD} --preserve" paperless
su -c "cd /home/paperless/paperless/src/ ; ./manage.py create_superuser_with_password --username paperless --email ${EMAIL} --password ${PASSWORD} --preserve" paperless

if [ ! -d /home/paperless/paperless/static ]; then
  # 167 static files copied to '/home/paperless/paperless/static'.
  su -c "cd /home/paperless/paperless/src/ ; ./manage.py collectstatic" paperless
fi

if [ ! -f /etc/apache2/sites-available/paperless.conf ]; then
  # Set-up apache
  cp /home/paperless/paperless/docs/examples/lxc/paperless.conf /etc/apache2/sites-available/
  a2dissite 000-default.conf
  a2ensite paperless.conf
  systemctl reload apache2
fi

sed -e "s:home/paperless/project/virtualenv/bin/python:usr/bin/python3:" \
     /home/paperless/paperless/scripts/paperless-consumer.service \
     >/etc/systemd/system/paperless-consumer.service

sed -i "s:/home/paperless/project/src/manage.py:/home/paperless/paperless/src/manage.py:" \
      /etc/systemd/system/paperless-consumer.service


systemctl enable paperless-consumer
systemctl start paperless-consumer

# convert-im6.q16: not authorized
# Security risk ?
# https://stackoverflow.com/questions/42928765/convertnot-authorized-aaaa-error-constitute-c-readimage-453
if [ -f /etc/ImageMagick-6/policy.xml ]; then
  mv /etc/ImageMagick-6/policy.xml /etc/ImageMagick-6/policy.xmlout
fi


================================================
FILE: docs/examples/lxc/paperless.conf
================================================
<VirtualHost *:80>
    ServerName paperless.lan

    Alias /static/ /home/paperless/paperless/static/
    <Directory /home/paperless/paperless/static>
        Require all granted
    </Directory>

    WSGIScriptAlias / /home/paperless/paperless/src/paperless/wsgi.py
    WSGIDaemonProcess paperless.lan user=paperless group=paperless threads=5 python-path=/home/paperless/paperless/src 
    WSGIProcessGroup paperless.lan

    <Directory /home/paperless/paperless/src/paperless>
        <Files wsgi.py>
            Require all granted
        </Files>
    </Directory>
</VirtualHost>


================================================
FILE: docs/extending.rst
================================================
.. _extending:

Extending Paperless
===================

For the most part, Paperless is monolithic, so extending it is often best
managed by way of modifying the code directly and issuing a pull request on
`GitHub`_.  However, over time the project has been evolving to be a little
more "pluggable" so that users can write their own stuff that talks to it.

.. _GitHub: https://github.com/the-paperless-project/paperless


.. _extending-parsers:

Parsers
-------

You can leverage Paperless' consumption model to have it consume files *other*
than ones handled by default like ``.pdf``, ``.jpg``, and ``.tiff``.  To do so,
you simply follow Django's convention of creating a new app, with a few key
requirements.


.. _extending-parsers-parserspy:

parsers.py
..........

In this file, you create a class that extends
``documents.parsers.DocumentParser`` and go about implementing the three
required methods:

* ``get_thumbnail()``: Returns the path to a file we can use as a thumbnail for
  this document.
* ``get_text()``: Returns the text from the document and only the text.
* ``get_date()``: If possible, this returns the date of the document, otherwise
  it should return ``None``.


.. _extending-parsers-signalspy:

signals.py
..........

At consumption time, Paperless emits a ``document_consumer_declaration``
signal which your module has to react to in order to let the consumer know
whether or not it's capable of handling a particular file.  Think of it like
this:

1. Consumer finds a file in the consumption directory.
2. It asks all the available parsers: *"Hey, can you handle this file?"*
3. Each parser responds with either ``None`` meaning they can't handle the
   file, or a dictionary in the following format:

.. code:: python

    {
        "parser": <the class name>,
        "weight": <an integer>
    }

The consumer compares the ``weight`` values from all respondents and uses the
class with the highest value to consume the document.  The default parser,
``RasterisedDocumentParser`` has a weight of ``0``.


.. _extending-parsers-appspy:

apps.py
.......

This is a standard Django file, but you'll need to add some code to it to
connect your parser to the ``document_consumer_declaration`` signal.


.. _extending-parsers-finally:

Finally
.......

The last step is to update ``settings.py`` to include your new module.
Eventually, this will be dynamic, but at the moment, you have to edit the
``INSTALLED_APPS`` section manually.  Simply add the path to your AppConfig to
the list like this:

.. code:: python

    INSTALLED_APPS = [
        ...
        "my_module.apps.MyModuleConfig",
        ...
    ]

Order doesn't matter, but generally it's a good idea to place your module lower
in the list so that you don't end up accidentally overriding project defaults
somewhere.


.. _extending-parsers-example:

An Example
..........

The core Paperless functionality is based on this design, so if you want to see
what a parser module should look like, have a look at `parsers.py`_,
`signals.py`_, and `apps.py`_ in the `paperless_tesseract`_ module.

.. _parsers.py: https://github.com/the-paperless-project/paperless/blob/master/src/paperless_tesseract/parsers.py
.. _signals.py: https://github.com/the-paperless-project/paperless/blob/master/src/paperless_tesseract/signals.py
.. _apps.py: https://github.com/the-paperless-project/paperless/blob/master/src/paperless_tesseract/apps.py
.. _paperless_tesseract: https://github.com/the-paperless-project/paperless/blob/master/src/paperless_tesseract/


================================================
FILE: docs/guesswork.rst
================================================
.. _guesswork:

Guesswork
#########

During the consumption process, Paperless tries to guess some of the attributes
of the document it's looking at.  To do this it uses two approaches:


.. _guesswork-naming:

File Naming
===========

Any document you put into the consumption directory will be consumed, but if
you name the file right, it'll automatically set some values in the database
for you.  This is is the logic the consumer follows:

1. Try to find the correspondent, title, and tags in the file name following
   the pattern: ``Date - Correspondent - Title - tag,tag,tag.pdf``.  Note that
   the format of the date is **rigidly defined** as ``YYYYMMDDHHMMSSZ`` or
   ``YYYYMMDDZ``.  The ``Z`` refers "Zulu time" AKA "UTC".
   The tags are optional, so the format ``Date - Correspondent - Title.pdf``
   works as well.
2. If that doesn't work, we skip the date and try this pattern:
   ``Correspondent - Title - tag,tag,tag.pdf``.
3. If that doesn't work, we try to find the correspondent and title in the file
   name following the pattern: ``Correspondent - Title.pdf``.
4. If that doesn't work, just assume that the name of the file is the title.

So given the above, the following examples would work as you'd expect:

* ``20150314000700Z - Some Company Name - Invoice 2016-01-01 - money,invoices.pdf``
* ``20150314Z - Some Company Name - Invoice 2016-01-01 - money,invoices.pdf``
* ``Some Company Name - Invoice 2016-01-01 - money,invoices.pdf``
* ``Another Company - Letter of Reference.jpg``
* ``Dad's Recipe for Pancakes.png``

These however wouldn't work:

* ``2015-03-14 00:07:00 UTC - Some Company Name, Invoice 2016-01-01, money, invoices.pdf``
* ``2015-03-14 - Some Company Name, Invoice 2016-01-01, money, invoices.pdf``
* ``Some Company Name, Invoice 2016-01-01, money, invoices.pdf``
* ``Another Company- Letter of Reference.jpg``

Do I have to be so strict about naming?
---------------------------------------
Rather than using the strict document naming rules, one can also set the option
``PAPERLESS_FILENAME_DATE_ORDER`` in ``paperless.conf`` to any date order
that is accepted by dateparser_. Doing so will cause ``paperless`` to default
to any date format that is found in the title, instead of a date pulled from
the document's text, without requiring the strict formatting of the document
filename as described above.

.. _dateparser: https://github.com/scrapinghub/dateparser/blob/v0.7.0/docs/usage.rst#settings

Transforming filenames for parsing
----------------------------------
Some devices can't produce filenames that can be parsed by the default
parser. By configuring the option ``PAPERLESS_FILENAME_PARSE_TRANSFORMS`` in
``paperless.conf`` one can add transformations that are applied to the filename
before it's parsed.

The option contains a list of dictionaries of regular expressions (key:
``pattern``) and replacements (key: ``repl``) in JSON format, which are
applied in order by passing them to ``re.subn``. Transformation stops
after the first match, so at most one transformation is applied. The general
syntax is

.. code:: python

   [{"pattern":"pattern1", "repl":"repl1"}, {"pattern":"pattern2", "repl":"repl2"}, ..., {"pattern":"patternN", "repl":"replN"}]

The example below is for a Brother ADS-2400N, a scanner that allows
different names to different hardware buttons (useful for handling
multiple entities in one instance), but insists on adding ``_<count>``
to the filename.

.. code:: python

   # Brother profile configuration, support "Name_Date_Count" (the default
   # setting) and "Name_Count" (use "Name" as tag and "Count" as title).
   PAPERLESS_FILENAME_PARSE_TRANSFORMS=[{"pattern":"^([a-z]+)_(\\d{8})_(\\d{6})_([0-9]+)\\.", "repl":"\\2\\3Z - \\4 - \\1."}, {"pattern":"^([a-z]+)_([0-9]+)\\.", "repl":" - \\2 - \\1."}]

.. _guesswork-content:

Reading the Document Contents
=============================

After the consumer has tried to figure out what it could from the file name,
it starts looking at the content of the document itself.  It will compare the
matching algorithms defined by every tag and correspondent already set in your
database to see if they apply to the text in that document.  In other words,
if you defined a tag called ``Home Utility`` that had a ``match`` property of
``bc hydro`` and a ``matching_algorithm`` of ``literal``, Paperless will
automatically tag your newly-consumed document with your ``Home Utility`` tag
so long as the text ``bc hydro`` appears in the body of the document somewhere.

The matching logic is quite powerful, and supports searching the text of your
document with different algorithms, and as such, some experimentation may be
necessary to get things Just Right.


.. _guesswork-content-howto:

How Do I Set Up These Matching Algorithms?
------------------------------------------

Setting up of the algorithms is easily done through the admin interface.  When
you create a new correspondent or tag, there are optional fields for matching
text and matching algorithm.  From the help info there:

.. note::

    Which algorithm you want to use when matching text to the OCR'd PDF.  Here,
    "any" looks for any occurrence of any word provided in the PDF, while "all"
    requires that every word provided appear in the PDF, albeit not in the
    order provided.  A "literal" match means that the text you enter must
    appear in the PDF exactly as you've entered it, and "regular expression"
    uses a regex to match the PDF.  If you don't know what a regex is, you
    probably don't want this option.

When using the "any" or "all" matching algorithms, you can search for terms
that consist of multiple words by enclosing them in double quotes. For example,
defining a match text of ``"Bank of America" BofA`` using the "any" algorithm,
will match documents that contain either "Bank of America" or "BofA", but will
not match documents containing "Bank of South America".

Then just save your tag/correspondent and run another document through the
consumer.  Once complete, you should see the newly-created document,
automatically tagged with the appropriate data.


================================================
FILE: docs/index.rst
================================================
.. _index:

Paperless
=========

Paperless is a simple Django application running in two parts:
a :ref:`consumer <utilities-consumer>` (the thing that does the indexing) and
the :ref:`webserver <utilities-webserver>` (the part that lets you search &
download already-indexed documents). If you want to learn more about its
functions keep on reading after the installation section.


.. _index-why-this-exists:

Why This Exists
===============

Paper is a nightmare.  Environmental issues aside, there's no excuse for it in
the 21st century.  It takes up space, collects dust, doesn't support any form
of a search feature, indexing is tedious, it's heavy and prone to damage &
loss.

I wrote this to make "going paperless" easier.  I do not have to worry about
finding stuff again. I feed documents right from the post box into the scanner
and then shred them.  Perhaps you might find it useful too.




Contents
========

.. toctree::
   :maxdepth: 2

   requirements
   setup
   consumption
   api
   utilities
   guesswork
   migrating
   customising
   extending
   troubleshooting
   contributing
   scanners
   screenshots
   changelog


================================================
FILE: docs/migrating.rst
================================================
.. _migrating:

Migrating, Updates, and Backups
===============================

As Paperless is still under active development, there's a lot that can change
as software updates roll out.  You should backup often, so if anything goes
wrong during an update, you at least have a means of restoring to something
usable.  Thankfully, there are automated ways of backing up, restoring, and
updating the software.


.. _migrating-backup:

Backing Up
----------

So you're bored of this whole project, or you want to make a remote backup of
your files for whatever reason.  This is easy to do, simply use the
:ref:`exporter <utilities-exporter>` to dump your documents and database out
into an arbitrary directory.


.. _migrating-restoring:

Restoring
---------

Restoring your data is just as easy, since nearly all of your data exists either
in the file names, or in the contents of the files themselves.  You just need to
create an empty database (just follow the
:ref:`installation instructions <setup-installation>` again) and then import the
``tags.json`` file you created as part of your backup.  Lastly, copy your
exported documents into the consumption directory and start up the consumer.

.. code-block:: shell-session

    $ cd /path/to/project
    $ rm data/db.sqlite3  # Delete the database
    $ cd src
    $ ./manage.py migrate  # Create the database
    $ ./manage.py createsuperuser
    $ ./manage.py loaddata /path/to/arbitrary/place/tags.json
    $ cp /path/to/exported/docs/* /path/to/consumption/dir/
    $ ./manage.py document_consumer

Importing your data if you are :ref:`using Docker <setup-installation-docker>`
is almost as simple:

.. code-block:: shell-session

    # Stop and remove your current containers
    $ docker-compose stop
    $ docker-compose rm -f

    # Recreate them, add the superuser
    $ docker-compose up -d
    $ docker-compose run --rm webserver createsuperuser

    # Load the tags
    $ cat /path/to/arbitrary/place/tags.json | docker-compose run --rm webserver loaddata_stdin -

    # Load your exported documents into the consumption directory
    # (How you do this highly depends on how you have set this up)
    $ cp /path/to/exported/docs/* /path/to/mounted/consumption/dir/

After loading the documents into the consumption directory the consumer will
immediately start consuming the documents.


.. _migrating-updates:

Updates
-------

For the most part, all you have to do to update Paperless is run ``git pull``
on the directory containing the project files, and then use Django's
``migrate`` command to execute any database schema updates that might have been
rolled in as part of the update:

.. code-block:: shell-session

    $ cd /path/to/project
    $ git pull
    $ pip install -r requirements.txt
    $ cd src
    $ ./manage.py migrate

Note that it's possible (even likely) that while ``git pull`` may update some
files, the ``migrate`` step may not update anything.  This is totally normal.

Additionally, as new features are added, the ability to control those features
is typically added by way of an environment variable set in ``paperless.conf``.
You may want to take a look at the ``paperless.conf.example`` file to see if
there's anything new in there compared to what you've got in ``/etc``.

If you are :ref:`using Docker <setup-installation-docker>` the update process
is similar:

.. code-block:: shell-session

    $ cd /path/to/project
    $ git pull
    $ docker build -t paperless .
    $ docker-compose run --rm consumer migrate
    $ docker-compose up -d

If ``git pull`` doesn't report any changes, there is no need to continue with
the remaining steps.


================================================
FILE: docs/requirements.rst
================================================
.. _requirements:

Requirements
============

You need a Linux machine or Unix-like setup (theoretically an Apple machine
should work) that has the following software installed:

* `Python3`_ (with development libraries, pip and virtualenv)
* `GNU Privacy Guard`_
* `Tesseract`_, plus its language files matching your document base.
* `Imagemagick`_ version 6.7.5 or higher
* `unpaper`_
* `libpoppler-cpp-dev`_ PDF rendering library
* `optipng`_

.. _Python3: https://python.org/
.. _GNU Privacy Guard: https://gnupg.org
.. _Tesseract: https://github.com/tesseract-ocr
.. _Imagemagick: http://imagemagick.org/
.. _unpaper: https://github.com/unpaper/unpaper
.. _libpoppler-cpp-dev: https://poppler.freedesktop.org/
.. _optipng: http://optipng.sourceforge.net/

Notably, you should confirm how you access your Python3 installation.  Many
Linux distributions will install Python3 in parallel to Python2, using the
names ``python3`` and ``python`` respectively.  The same goes for ``pip3`` and
``pip``.  Running Paperless with Python2 will likely break things, so make sure
that you're using the right version.

For the purposes of simplicity, ``python`` and ``pip`` is used everywhere to
refer to their Python3 versions.

In addition to the above, there are a number of Python requirements, all of
which are listed in a file called ``requirements.txt`` in the project root
directory.

If you're not working on a virtual environment (like Docker), you
should probably be using a virtualenv, but that's your call.  The reasons why
you might choose a virtualenv or not aren't really within the scope of this
document.  Needless to say if you don't know what a virtualenv is, you should
probably figure that out before continuing.


.. _requirements-apple:

Problems with Imagemagick & PDFs
--------------------------------

Some users have `run into problems`_ with getting ImageMagick to do its thing
with PDFs.  Often this is the case with Apple systems using HomeBrew, but other
Linuxes have been a problem as well.  The solution appears to be to install
ghostscript as well as ImageMagick:

.. _run into problems: https://github.com/the-paperless-project/paperless/issues/25

.. code:: bash

    $ brew install ghostscript
    $ brew install imagemagick
    $ brew install libmagic


.. _requirements-baremetal:

Python-specific Requirements: No Virtualenv
-------------------------------------------

If you don't care to use a virtual env, then installation of the Python
dependencies is easy:

.. code:: bash

    $ pip install --user --requirement /path/to/paperless/requirements.txt

This will download and install all of the requirements into
``${HOME}/.local``.  Remember that your distribution may be using ``pip3`` as
mentioned above.


.. _requirements-virtualenv:

Python-specific Requirements: Virtualenv
----------------------------------------

Using a virtualenv for this is pretty straightforward: create a virtualenv,
enter it, and install the requirements using the ``requirements.txt`` file:

.. code:: bash

    $ virtualenv --python=/path/to/python3 /path/to/arbitrary/directory
    $ . /path/to/arbitrary/directory/bin/activate
    $ pip install  --requirement /path/to/paperless/requirements.txt

Now you're ready to go.  Just remember to enter (activate) your virtualenv
whenever you want to use Paperless.


.. _requirements-documentation:

Documentation
-------------

As generation of the documentation is not required for the use of Paperless,
dependencies for this process are not included in ``requirements.txt``.  If
you'd like to generate your own docs locally, you'll need to:

.. code:: bash

    $ pip install sphinx

and then cd into the ``docs`` directory and type ``make html``.

If you are using Docker, you can use the following commands to build the
documentation and run a webserver serving it on `port 8001`_:

.. code:: bash

    $ pwd
    /path/to/paperless

    $ docker build -t paperless:docs -f docs/Dockerfile .
    $ docker run --rm -it -p "8001:8000" paperless:docs

.. _port 8001: http://127.0.0.1:8001


================================================
FILE: docs/requirements.txt
================================================


================================================
FILE: docs/scanners.rst
================================================
.. _scanners:

Scanner Recommendations
=======================

As Paperless operates by watching a folder for new files, doesn't care what
scanner you use, but sometimes finding a scanner that will write to an FTP,
NFS, or SMB server can be difficult.  This page is here to help you find one
that works right for you based on recommentations from other Paperless users.

Physical scanners
-----------------

+---------+----------------+-----+-----+-----+----------------+
| Brand   | Model          | Supports        | Recommended By |
+---------+----------------+-----+-----+-----+----------------+
|         |                | FTP | NFS | SMB |                |
+=========+================+=====+=====+=====+================+
| Brother | `ADS-1500W`_   | yes | no  | yes | `danielquinn`_ |
+---------+----------------+-----+-----+-----+----------------+
| Brother | `MFC-J6930DW`_ | yes |     |     | `ayounggun`_   |
+---------+----------------+-----+-----+-----+----------------+
| Brother | `MFC-J5910DW`_ | yes |     |     | `bmsleight`_   |
+---------+----------------+-----+-----+-----+----------------+
| Brother | `MFC-9142CDN`_ | yes |     | yes | `REOLDEV`_     |
+---------+----------------+-----+-----+-----+----------------+
| Fujitsu | `ix500`_       | yes |     | yes | `eonist`_      |
+---------+----------------+-----+-----+-----+----------------+

.. _ADS-1500W: https://www.brother.ca/en/p/ads1500w
.. _MFC-J6930DW: https://www.brother.ca/en/p/MFCJ6930DW
.. _MFC-J5910DW: https://www.brother.co.uk/printers/inkjet-printers/mfcj5910dw
.. _MFC-9142CDN: https://www.brother.co.uk/printers/laser-printers/mfc9140cdn
.. _ix500: http://www.fujitsu.com/us/products/computing/peripheral/scanners/scansnap/ix500/

.. _danielquinn: https://github.com/danielquinn
.. _ayounggun: https://github.com/ayounggun
.. _bmsleight: https://github.com/bmsleight
.. _eonist: https://github.com/eonist
.. _REOLDEV: https://github.com/REOLDEV

Mobile phone software
-----------------------

You can use your phone to "scan" documents. The regular camera app will work, but may have too low contrast for OCR to work well. Apps specifically for scanning are recommended.

+-------------------+----------------+-----+-----+-----+-------+--------+----------------+
| Name              | OS             | Supports                         | Recommended By |
+-------------------+----------------+-----+-----+-----+-------+--------+----------------+
|                   |                | FTP | NFS | SMB | Email | WebDav |                |
+===================+================+=====+=====+=====+=======+========+================+
| `Genius Scan`_    | Android        | yes | no  | yes | yes   | yes    | `hannahswain`_ |
+-------------------+----------------+-----+-----+-----+-------+--------+----------------+


.. _Genius Scan: https://play.google.com/store/apps/details?id=com.thegrizzlylabs.geniusscan.free

.. _hannahswain: https://github.com/hannahswain


================================================
FILE: docs/screenshots.rst
================================================
.. _screenshots:

Screenshots
===========

Once everything is set-up login to paperless using the web front-end

.. image:: ./_static/Screenshot_first_run_login.png 

Nice clean interface

.. image:: ./_static/Screenshot_first_logged.png 

Some documents loaded in via ftp or using the scanners ftp. 

.. image:: ./_static/Screenshot_upload_and_scanned.png 


================================================
FILE: docs/setup.rst
================================================
.. _setup:

Setup
=====

Paperless isn't a very complicated app, but there are a few components, so some
basic documentation is in order.  If you follow along in this document and
still have trouble, please open an `issue on GitHub`_ so I can fill in the
gaps.

.. _issue on GitHub: https://github.com/the-paperless-project/paperless/issues


.. _setup-download:

Download
--------

The source is currently only available via GitHub, so grab it from there,
either by using ``git``:

.. code:: bash

    $ git clone https://github.com/the-paperless-project/paperless.git
    $ cd paperless

or just download the tarball and go that route:

.. code:: bash

    $ cd to the directory where you want to run Paperless
    $ wget https://github.com/the-paperless-project/paperless/archive/master.zip
    $ unzip master.zip
    $ cd paperless-master


.. _setup-installation:

Installation & Configuration
----------------------------

You can go multiple routes with setting up and running Paperless:

 * The `bare metal route`_
 * The `docker route`_
 * A suggested `linux containers route`_


The `docker route`_ is quick & easy.

The `bare metal route`_ is a bit more complicated to setup but makes it easier
should you want to contribute some code back.

The `linux containers route`_ is quick, but makes alot of assumptions on the 
set-up, on the other hand the script could be used to install on a base
debian or ubuntu server.

.. _docker route: setup-installation-docker_
.. _bare metal route: setup-installation-bare-metal_
.. _Docker Machine: https://docs.docker.com/machine/
.. _linux containers route: setup-installation-linux-containers_

.. _setup-installation-bare-metal:

Standard (Bare Metal)
+++++++++++++++++++++

1. Install the requirements as per the :ref:`requirements <requirements>` page.
2. Within the extract of master.zip go to the ``src`` directory.
3. Copy ``../paperless.conf.example`` to ``/etc/paperless.conf`` and open it in
   your favourite editor.  As this file contains passwords.  It should only be
   readable by user root and paperless!  Set the values for:

   Set the values for:

    * ``PAPERLESS_CONSUMPTION_DIR``: this is where your documents will be
      dumped to be consumed by Paperless.
    * ``PAPERLESS_OCR_THREADS``: this is the number of threads the OCR process
      will spawn to process document pages in parallel.
    * ``PAPERLESS_PASSPHRASE``: this is only required if you want to use GPG to
      encrypt your document files.  This is the passphrase Paperless uses to
      encrypt/decrypt the original documents.  Don't worry about defining this
      if you don't want to use encryption (the default).

   Note also that if you're using the ``runserver`` as mentioned below, you
   should make sure that PAPERLESS_DEBUG="true" or is just commented out as
   this is the default.

4. Initialise the SQLite database with ``./manage.py migrate``.
5. Collect the static files for the webserver with ``./manage.py collectstatic``.
6. Create a user for your Paperless instance with
   ``./manage.py createsuperuser``. Follow the prompts to create your user.
7. Start the webserver with ``./manage.py runserver <IP>:<PORT>``.
   If no specific IP or port is given, the default is ``127.0.0.1:8000`` also
   known as http://localhost:8000/.
   You should now be able to visit your (empty) installation at
   `Paperless webserver`_ or whatever you chose before.  You can login with the
   user/pass you created in #5.

8. In a separate window, change to the ``src`` directory in this repo again,
   but this time, you should start the consumer script with
   ``./manage.py document_consumer``.
9. Scan something or put a file into the  ``CONSUMPTION_DIR``.
10. Wait a few minutes
11. Visit the document list on your webserver, and it should be there, indexed
    and downloadable.

.. caution::

    This installation is not secure. Once everything is working head over to
    `Making things more permanent`_

.. _Paperless webserver: http://127.0.0.1:8000
.. _Making things more permanent: setup-permanent_

.. _setup-installation-docker:

Docker Method
+++++++++++++

1. Install `Docker`_.

   .. caution::

      As mentioned earlier, this guide assumes that you use Docker natively
      under Linux. If you are using `Docker Machine`_ under Mac OS X or
      Windows, you will have to adapt IP addresses, volume-mounting, command
      execution and maybe more.

2. Install `docker-compose`_. [#compose]_

   .. caution::

       If you want to use the included ``docker-compose.yml.example`` file, you
       need to have at least Docker version **1.12.0** and docker-compose
       version **1.9.0**.

       See the `Docker installation guide`_ on how to install the current
       version of Docker for your operating system or Linux distribution of
       choice. To get an up-to-date version of docker-compose, follow the
       `docker-compose installation guide`_ if your package repository doesn't
       include it.

       .. _Docker installation guide: https://docs.docker.com/engine/installation/
       .. _docker-compose installation guide: https://docs.docker.com/compose/install/

3. Create a copy of ``docker-compose.yml.example`` as ``docker-compose.yml``
   and a copy of ``docker-compose.env.example`` as ``docker-compose.env``.
   You'll be editing both these files: taking a copy ensures that you can
   ``git pull`` to receive updates without risking merge conflicts with your
   modified versions of the configuration files.
4. Modify ``docker-compose.yml`` to your preferences, following the
   instructions in comments in the file. The only change that is a hard
   requirement is to specify where the consumption directory should
   mount.[#dockercomposeyml]_

	 .. caution::

	     If you are using NFS mounts for the consume directory you also need to
			 change the command to turn off inotify as it doesn't work with NFS

			 ``command: ["document_consumer", "--no-inotify"]``


5. Modify ``docker-compose.env`` and adapt the following environment variables:

   ``PAPERLESS_PASSPHRASE``
     This is the passphrase Paperless uses to encrypt/decrypt the original
     document.  If you aren't planning on using GPG encryption, you can just
     leave this undefined.

   ``PAPERLESS_OCR_THREADS``
     This is the number of threads the OCR process will spawn to process
     document pages in parallel. If the variable is not set, Python determines
     the core-count of your CPU and uses that value.

   ``PAPERLESS_OCR_LANGUAGES``
     If you want the OCR to recognize other languages in addition to the
     default English, set this parameter to a space separated list of
     three-letter language-codes after `ISO 639-2/T`_. For a list of available
     languages -- including their three letter codes -- see the
     `Alpine packagelist`_.

   ``USERMAP_UID`` and ``USERMAP_GID``
     If you want to mount the consumption volume (directory ``/consume`` within
     the containers) to a host-directory -- which you probably want to do --
     access rights might be an issue. The default user and group ``paperless``
     in the containers have an id of 1000. The containers will enforce that the
     owning group of the consumption directory will be ``paperless`` to be able
     to delete consumed documents. If your host-system has a group with an ID
     of 1000 and you don't want this group to have access rights to the
     consumption directory, you can use ``USERMAP_GID`` to change the id in the
     container and thus the one of the consumption directory. Furthermore, you
     can change the id of the default user as well using ``USERMAP_UID``.

  ``PAPERLESS_USE_SSL``
    If you want Paperless to use SSL for the user interface, set this variable
    to ``true``. You also need to copy your certificate and key to the ``data``
    directory, named ``ssl.cert`` and ``ssl.key``.
    This is not an ideal solution and, if possible, a reverse proxy with nginx
    is preferred.

6. Run ``docker-compose up -d``. This will create and start the necessary
   containers.
7. To be able to login, you will need a super user. To create it, execute the
   following command:

   .. code-block:: shell-session

       $ docker-compose run --rm webserver createsuperuser

   This will prompt you to set a username (default ``paperless``), an optional
   e-mail address and finally a password.
8. The default ``docker-compose.yml`` exports the webserver on your local port
   8000. If you haven't adapted this, you should now be able to visit your
   `Paperless webserver`_ at ``http://127.0.0.1:8000`` (or 
   ``https://127.0.0.1:8000`` if you enabled SSL). You can login with the
   user and password you just created.
9. Add files to consumption directory the way you prefer to. Following are two
   possible options:

   1. Mount the consumption directory to a local host path by modifying your
      ``docker-compose.yml``:

      .. code-block:: diff

         diff --git a/docker-compose.yml b/docker-compose.yml
         --- a/docker-compose.yml
         +++ b/docker-compose.yml
         @@ -17,9 +18,8 @@ services:
                  volumes:
                      - paperless-data:/usr/src/paperless/data
                      - paperless-media:/usr/src/paperless/media
         -            - /consume
         +            - /local/path/you/choose:/consume

      .. danger::

          While the consumption container will ensure at startup that it can
          **delete** a consumed file from a host-mounted directory, it might
          not be able to **read** the document in the first place if the access
          rights to the file are incorrect.

          Make sure that the documents you put into the consumption directory
          will either be readable by everyone (``chmod o+r file.pdf``) or
          readable by the default user or group id 1000 (or the one you have
          set with ``USERMAP_UID`` or ``USERMAP_GID`` respectively).

   2. Use ``docker cp`` to copy your files directly into the container:

      .. code-block:: shell-session

         $ # Identify your containers
         $ docker-compose ps
                 Name                       Command                State     Ports
         -------------------------------------------------------------------------
         paperless_consumer_1    /sbin/docker-entrypoint.sh ...   Exit 0
         paperless_webserver_1   /sbin/docker-entrypoint.sh ...   Exit 0

         $ docker cp /path/to/your/file.pdf paperless_consumer_1:/consume

      ``docker cp`` is a one-shot-command, just like ``cp``. This means that
      every time you want to consume a new document, you will have to execute
      ``docker cp`` again. You can of course automate this process, but option
      1 is generally the preferred one.

      .. danger::

          ``docker cp`` will change the owning user and group of a copied file
          to the acting user at the destination, which will be ``root``.

          You therefore need to ensure that the documents you want to copy into
          the container are readable by everyone (``chmod o+r file.pdf``)
          before copying them.


.. _Docker: https://www.docker.com/
.. _docker-compose: https://docs.docker.com/compose/install/
.. _ISO 639-2/T: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
.. _Alpine packagelist: https://pkgs.alpinelinux.org/packages?name=tesseract-ocr-data*&arch=x86_64

.. [#compose] You of course don't have to use docker-compose, but it
   simplifies deployment immensely. If you know your way around Docker, feel
   free to tinker around without using compose!

.. [#dockercomposeyml] If you're upgrading your docker-compose images from
   version 1.1.0 or earlier, you might need to change in the
   ``docker-compose.yml`` file the ``image: pitkley/paperless`` directive in
   both the ``webserver`` and ``consumer`` sections to ``build: ./`` as per the
   newer ``docker-compose.yml.example`` file


.. _setup-permanent:

Making Things a Little more Permanent
-------------------------------------

Once you've tested things and are happy with the work flow, you should secure
the installation and automate the process of starting the webserver and
consumer.


.. _setup-permanent-webserver:

Using a Real Webserver
++++++++++++++++++++++

The default is to use Django's development server, as that's easy and does the
job well enough on a home network. However it is heavily discouraged to use
it for more than that.

If you want to do things right you should use a real webserver capable of
handling more than one thread. You will also have to let the webserver serve
the static files (CSS, JavaScript) from the directory configured in
``PAPERLESS_STATICDIR``.  The default static files directory is ``../static``.

For that you need to activate your virtual environment and collect the static
files with the command:

.. code:: bash

    $ cd <paperless directory>/src
    $ ./manage.py collectstatic


Apache
~~~~~~

This is a configuration supplied by `steckerhalter`_ on GitHub.  It uses Apache
and mod_wsgi, with a Paperless installation in ``/home/paperless/``:

.. code:: apache

    <VirtualHost *:80>
        ServerName example.com

        Alias /static/ /home/paperless/paperless/static/
        <Directory /home/paperless/paperless/static>
            Require all granted
        </Directory>

        WSGIScriptAlias / /home/paperless/paperless/src/paperless/wsgi.py
        WSGIDaemonProcess example.com user=paperless group=paperless threads=5 python-path=/home/paperless/paperless/src:/home/paperless/.env/lib/python3.6/site-packages
        WSGIProcessGroup example.com

        <Directory /home/paperless/paperless/src/paperless>
            <Files wsgi.py>
                Require all granted
            </Files>
        </Directory>
    </VirtualHost>

.. _steckerhalter: https://github.com/steckerhalter


Nginx + Gunicorn
~~~~~~~~~~~~~~~~

If you're using Nginx, the most common setup is to combine it with a
Python-based server like Gunicorn so that Nginx is acting as a proxy.  Below is
a copy of a simple Nginx configuration fragment making use of a gunicorn
instance listening on localhost port 8000.

.. code:: nginx

    server {
        listen 80;

        index index.html index.htm index.php;
        access_log /var/log/nginx/paperless_access.log;
        error_log /var/log/nginx/paperless_error.log;

        location /static {

            autoindex on;
            alias <path-to-paperless-static-directory>;

        }

        location / {

            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_pass http://127.0.0.1:8000;
        }
    }


The gunicorn server can be started with the command:

.. code-block:: shell

    $ <path-to-paperless-virtual-environment>/bin/gunicorn --pythonpath=<path-to-paperless>/src paperless.wsgi -w 2


.. _setup-permanent-standard-systemd:

Standard (Bare Metal + Systemd)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you're running on a bare metal system that's using Systemd, you can use the
service unit files in the ``scripts`` directory to set this up.

1. You'll need to create a group and user called ``paperless`` (without login)
2. Setup Paperless to be in a place that this new user can read and write to.
3. Ensure ``/etc/paperless`` is readable by the ``paperless`` user.
4. Copy the service file from the ``scripts`` directory to
   ``/etc/systemd/system``.

.. code-block:: bash

    $ cp /path/to/paperless/scripts/paperless-consumer.service /etc/systemd/system/
    $ cp /path/to/paperless/scripts/paperless-webserver.service /etc/systemd/system/

5. Edit the service file to point the ``ExecStart`` line to the proper location
   of your paperless install, referencing the appropriate Python binary. For
   example:
   ``ExecStart=/path/to/python3 /path/to/paperless/src/manage.py document_consumer``.
6. Start and enable (so they start on boot) the services.

.. code-block:: bash

    $ systemctl enable paperless-consumer
    $ systemctl enable paperless-webserver
    $ systemctl start paperless-consumer
    $ systemctl start paperless-webserver


.. _setup-permanent-standard-upstart:

Standard (Bare Metal + Upstart)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Ubuntu 14.04 and earlier use the `Upstart`_ init system to start services
during the boot process. To configure Upstart to run Paperless automatically
after restarting your system:

1. Change to the directory where Upstart's configuration files are kept:
   ``cd /etc/init``
2. Create a new file: ``sudo nano paperless-server.conf``
3. In the newly-created file enter::

    start on (local-filesystems and net-device-up IFACE=eth0)
    stop on shutdown

    respawn
    respawn limit 10 5

    script
      exec <path to paperless virtual environment>/bin/gunicorn --pythonpath=<path to parperless>/src paperless.wsgi -w 2
    end script

   Note that you'll need to replace ``/srv/paperless/src/manage.py`` with the
   path to the ``manage.py`` script in your installation directory.

  If you are using a network interface other than ``eth0``, you will have to
  change ``IFACE=eth0``. For example, if you are connected via WiFi, you will
  likely need to replace ``eth0`` above with ``wlan0``. To see all interfaces,
  run ``ifconfig -a``.

  Save the file.

4. Create a new file: ``sudo nano paperless-consumer.conf``

5. In the newly-created file enter::

    start on (local-filesystems and net-device-up IFACE=eth0)
    stop on shutdown

    respawn
    respawn limit 10 5

    script
      exec <path to paperless virtual environment>/bin/python <path to parperless>/manage.py document_consumer
    end script

  Replace the path placeholder and ``eth0`` with the appropriate value and save the file.

These two configuration files together will start both the Paperless webserver
and document consumer processes when the file system and network interface
specified is available after boot. Furthermore, if either process ever exits
unexpectedly, Upstart will try to restart it a maximum of 10 times within a 5
second period.

.. _Upstart: http://upstart.ubuntu.com/


.. _setup-permanent-docker:

Docker
~~~~~~

If you're using Docker, you can set a restart-policy_ in the
``docker-compose.yml`` to have the containers automatically start with the
Docker daemon.

.. _restart-policy: https://docs.docker.com/engine/reference/commandline/run/#restart-policies-restart


.. _setup-installation-linux-containers:

Suggested way for Linux Container Method
++++++++++++++++++++++++++++++++++++++++

This method uses some rigid assumptions, for the best set-up:-

 * Ubuntu lts as the container
 * Apache as the webserver
 * proftpd as ftp server
 * ftpupload as the ftp user
 * paperless as the main user for website 
 * http://paperless.lan is the desired lan url
 * LXC set to give ip addresses on your lan

This could also be used as an install on a base debain/ubuntu server, 
if the above assumptions are acceptable.

1. Install lxc


2. Lanch paperless container

.. code:: bash

    $ lxc launch ubuntu: paperless

3. Run install script within container

.. code:: bash

    $ lxc exec paperless -- sh -c "wget https://raw.githubusercontent.com/the-paperless-project/paperless/master/docs/examples/lxc/lxc-install.sh && /bin/bash lxc-install.sh --email"

The script will ask you for an ftpupload password.  
As well as the super-user for paperless web front-end. 
After around 10 mins, http://paperless.lan is ready and
ftp://paperless.lan with user: ftpupload

See the `Installation recording <_static/lxc-install.svg>`_.



================================================
FILE: docs/troubleshooting.rst
================================================
.. _troubleshooting:

Troubleshooting
===============

.. _troubleshooting-languagemissing:

Consumer warns ``OCR for XX failed``
------------------------------------

If you find the OCR accuracy to be too low, and/or the document consumer warns
that ``OCR for XX failed, but we're going to stick with what we've got since
FORGIVING_OCR is enabled``, then you might need to install the
`Tesseract language files <http://packages.ubuntu.com/search?keywords=tesseract-ocr>`_
marching your document's languages.

As an example, if you are running Paperless from any Ubuntu or Debian
box, and your documents are written in Spanish you may need to run::

    apt-get install -y tesseract-ocr-spa


.. _troubleshooting-convertpixelcache:

Consumer dies with ``convert: unable to extent pixel cache``
------------------------------------------------------------

During the consumption process, Paperless invokes ImageMagick's ``convert``
program to translate the source document into something that the OCR engine can
understand and this can burn a Very Large amount of memory if the original
document is rather long.  Similarly, if your system doesn't have a lot of
memory to begin with (ie. a Raspberry Pi), then this can happen for even
medium-sized documents.

The solution is to tell ImageMagick *not* to Use All The RAM, as is its
default, and instead tell it to used a fixed amount.  ``convert`` will then
break up the job into hundreds of individual files and use them to slowly
compile the finished image.  Simply set ``PAPERLESS_CONVERT_MEMORY_LIMIT`` in
``/etc/paperless.conf`` to something like ``32000000`` and you'll limit
``convert`` to 32MB.  Fiddle with this value as you like.

**HOWEVER**: Simply setting this value may not be enough on system where
``/tmp`` is mounted as tmpfs, as this is where ``convert`` will write its
temporary files.  In these cases (most Systemd machines), you need to tell
ImageMagick to use a different space for its scratch work.  You do this by
setting ``PAPERLESS_CONVERT_TMPDIR`` in ``/etc/paperless.conf`` to somewhere
that's actually on a physical disk (and writable by the user running
Paperless), like ``/var/tmp/paperless`` or ``/home/my_user/tmp`` in a pinch.


.. _troubleshooting-decompressionbombwarning:

DecompressionBombWarning and/or no text in the OCR output
---------------------------------------------------------
Some users have had issues using Paperless to consume PDFs that were created
by merging Very Large Scanned Images into one PDF.  If this happens to you,
it's likely because the PDF you've created contains some very large pages
(millions of pixels) and the process of converting the PDF to a OCR-friendly
image is exploding.

Typically, this happens because the scanned images are created with a high
DPI and then rolled into the PDF with an assumed DPI of 72 (the default).
The best solution then is to specify the DPI used in the scan in the
conversion-to-PDF step.  So for example, if you scanned the original image
with a DPI of 300, then merging the images into the single PDF with
``convert`` should look like this:

.. code:: bash

    $ convert -density 300 *.jpg finished.pdf

For more information on this and situations like it, you should take a look
at `Issue #118`_ as that's where this tip originated.

.. _Issue #118: https://github.com/the-paperless-project/paperless/issues/118

================================================
FILE: docs/utilities.rst
================================================
.. _utilities:

Utilities
=========

There's basically three utilities to Paperless: the webserver, consumer, and
if needed, the exporter.  They're all detailed here.


.. _utilities-webserver:

The Webserver
-------------

At the heart of it, Paperless is a simple Django webservice, and the entire
interface is based on Django's standard admin interface.  Once running, visiting
the URL for your service delivers the admin, through which you can get a
detailed listing of all available documents, search for specific files, and
download whatever it is you're looking for.


.. _utilities-webserver-howto:

How to Use It
.............

The webserver is started via the ``manage.py`` script:

.. code-block:: shell-session

    $ /path/to/paperless/src/manage.py runserver

By default, the server runs on localhost, port 8000, but you can change this
with a few arguments, run ``manage.py --help`` for more information.

Add the option ``--noreload`` to reduce resource usage. Otherwise, the server
continuously polls all source files for changes to auto-reload them.

Note that when exiting this command your webserver will disappear.
If you want to run this full-time (which is kind of the point)
you'll need to have it start in the background -- something you'll need to
figure out for your own system.  To get you started though, there are Systemd
service files in the ``scripts`` directory.


.. _utilities-consumer:

The Consumer
------------

The consumer script runs in an infinite loop, constantly looking at a directory
for documents to parse and index.  The process is pretty straightforward:

1. Look in ``CONSUMPTION_DIR`` for a document.  If one is found, go to #2.
   If not, wait 10 seconds and try again.  On Linux, new documents are detected
   instantly via inotify, so there's no waiting involved.
2. Parse the document with Tesseract
3. Create a new record in the database with the OCR'd text
4. Attempt to automatically assign document attributes by doing some guesswork.
   Read up on the :ref:`guesswork documentation<
Download .txt
gitextract_yqrokexp/

├── .docker-hub-test
├── .editorconfig
├── .gitattributes
├── .gitignore
├── .travis.yml
├── CODE_OF_CONDUCT.md
├── Dockerfile
├── LICENSE
├── Pipfile
├── README-de.md
├── README-el.md
├── README.md
├── THANKS.md
├── ci/
│   └── deploy-docker
├── data/
│   └── .keep
├── docker-compose.env.example
├── docker-compose.yml.example
├── docs/
│   ├── Dockerfile
│   ├── Makefile
│   ├── _static/
│   │   ├── .keep
│   │   └── custom.css
│   ├── api.rst
│   ├── changelog.rst
│   ├── conf.py
│   ├── consumption.rst
│   ├── contributing.rst
│   ├── customising.rst
│   ├── examples/
│   │   └── lxc/
│   │       ├── lxc-install.sh
│   │       └── paperless.conf
│   ├── extending.rst
│   ├── guesswork.rst
│   ├── index.rst
│   ├── migrating.rst
│   ├── requirements.rst
│   ├── requirements.txt
│   ├── scanners.rst
│   ├── screenshots.rst
│   ├── setup.rst
│   ├── troubleshooting.rst
│   └── utilities.rst
├── management/
│   └── commands/
│       └── create_superuser_with_password.py
├── overrides/
│   └── README.md
├── paperless.conf.example
├── presentation/
│   ├── README.md
│   ├── contrib/
│   │   ├── font-awesome-4.3.0/
│   │   │   ├── css/
│   │   │   │   └── font-awesome.css
│   │   │   ├── fonts/
│   │   │   │   └── FontAwesome.otf
│   │   │   ├── less/
│   │   │   │   ├── animated.less
│   │   │   │   ├── bordered-pulled.less
│   │   │   │   ├── core.less
│   │   │   │   ├── fixed-width.less
│   │   │   │   ├── font-awesome.less
│   │   │   │   ├── icons.less
│   │   │   │   ├── larger.less
│   │   │   │   ├── list.less
│   │   │   │   ├── mixins.less
│   │   │   │   ├── path.less
│   │   │   │   ├── rotated-flipped.less
│   │   │   │   ├── stacked.less
│   │   │   │   └── variables.less
│   │   │   └── scss/
│   │   │       ├── _animated.scss
│   │   │       ├── _bordered-pulled.scss
│   │   │       ├── _core.scss
│   │   │       ├── _fixed-width.scss
│   │   │       ├── _icons.scss
│   │   │       ├── _larger.scss
│   │   │       ├── _list.scss
│   │   │       ├── _mixins.scss
│   │   │       ├── _path.scss
│   │   │       ├── _rotated-flipped.scss
│   │   │       ├── _stacked.scss
│   │   │       ├── _variables.scss
│   │   │       └── font-awesome.scss
│   │   └── google/
│   │       └── css/
│   │           └── lato.css
│   ├── css/
│   │   ├── print/
│   │   │   ├── paper.css
│   │   │   └── pdf.css
│   │   ├── reveal.css
│   │   ├── reveal.scss
│   │   └── theme/
│   │       ├── README.md
│   │       ├── beige.css
│   │       ├── black.css
│   │       ├── blood.css
│   │       ├── league.css
│   │       ├── moon.css
│   │       ├── night.css
│   │       ├── serif.css
│   │       ├── simple.css
│   │       ├── sky.css
│   │       ├── solarized.css
│   │       ├── source/
│   │       │   ├── beige.scss
│   │       │   ├── black.scss
│   │       │   ├── blood.scss
│   │       │   ├── league.scss
│   │       │   ├── moon.scss
│   │       │   ├── night.scss
│   │       │   ├── serif.scss
│   │       │   ├── simple.scss
│   │       │   ├── sky.scss
│   │       │   ├── solarized.scss
│   │       │   └── white.scss
│   │       ├── template/
│   │       │   ├── mixins.scss
│   │       │   ├── settings.scss
│   │       │   └── theme.scss
│   │       └── white.css
│   ├── index.html
│   ├── js/
│   │   └── reveal.js
│   ├── lib/
│   │   ├── css/
│   │   │   └── zenburn.css
│   │   ├── font/
│   │   │   ├── league-gothic/
│   │   │   │   ├── LICENSE
│   │   │   │   └── league-gothic.css
│   │   │   └── source-sans-pro/
│   │   │       ├── LICENSE
│   │   │       └── source-sans-pro.css
│   │   └── js/
│   │       ├── classList.js
│   │       └── html5shiv.js
│   └── plugin/
│       ├── highlight/
│       │   └── highlight.js
│       ├── leap/
│       │   └── leap.js
│       ├── markdown/
│       │   ├── example.html
│       │   ├── example.md
│       │   ├── markdown.js
│       │   └── marked.js
│       ├── math/
│       │   └── math.js
│       ├── multiplex/
│       │   ├── client.js
│       │   ├── index.js
│       │   └── master.js
│       ├── notes/
│       │   ├── notes.html
│       │   └── notes.js
│       ├── notes-server/
│       │   ├── client.js
│       │   ├── index.js
│       │   └── notes.html
│       ├── print-pdf/
│       │   └── print-pdf.js
│       ├── remotes/
│       │   └── remotes.js
│       ├── search/
│       │   └── search.js
│       └── zoom-js/
│           └── zoom.js
├── requirements.txt
├── resources/
│   └── logo/
│       └── print/
│           └── eps/
│               ├── Black logo - no background.eps
│               ├── Color logo - no background.eps
│               ├── Color logo with background.eps
│               └── White logo - no background.eps
├── scripts/
│   ├── docker-entrypoint.sh
│   ├── gunicorn.conf
│   ├── paperless-consumer.service
│   ├── paperless-webserver.service
│   └── post-consumption-example.sh
└── src/
    ├── documents/
    │   ├── __init__.py
    │   ├── actions.py
    │   ├── admin.py
    │   ├── apps.py
    │   ├── checks.py
    │   ├── consumer.py
    │   ├── filters.py
    │   ├── forms.py
    │   ├── loggers.py
    │   ├── mail.py
    │   ├── management/
    │   │   ├── __init__.py
    │   │   └── commands/
    │   │       ├── __init__.py
    │   │       ├── change_storage_type.py
    │   │       ├── document_consumer.py
    │   │       ├── document_correspondents.py
    │   │       ├── document_exporter.py
    │   │       ├── document_importer.py
    │   │       ├── document_logs.py
    │   │       ├── document_renamer.py
    │   │       ├── document_retagger.py
    │   │       └── loaddata_stdin.py
    │   ├── managers.py
    │   ├── migrations/
    │   │   ├── 0001_initial.py
    │   │   ├── 0002_auto_20151226_1316.py
    │   │   ├── 0003_sender.py
    │   │   ├── 0004_auto_20160114_1844.py
    │   │   ├── 0005_auto_20160123_0313.py
    │   │   ├── 0006_auto_20160123_0430.py
    │   │   ├── 0007_auto_20160126_2114.py
    │   │   ├── 0008_document_file_type.py
    │   │   ├── 0009_auto_20160214_0040.py
    │   │   ├── 0010_log.py
    │   │   ├── 0011_auto_20160303_1929.py
    │   │   ├── 0012_auto_20160305_0040.py
    │   │   ├── 0013_auto_20160325_2111.py
    │   │   ├── 0014_document_checksum.py
    │   │   ├── 0015_add_insensitive_to_match.py
    │   │   ├── 0016_auto_20170325_1558.py
    │   │   ├── 0017_auto_20170512_0507.py
    │   │   ├── 0018_auto_20170715_1712.py
    │   │   ├── 0019_add_consumer_user.py
    │   │   ├── 0020_document_added.py
    │   │   ├── 0021_document_storage_type.py
    │   │   ├── 0022_auto_20181007_1420.py
    │   │   ├── 0023_document_current_filename.py
    │   │   └── __init__.py
    │   ├── mixins.py
    │   ├── models.py
    │   ├── parsers.py
    │   ├── serialisers.py
    │   ├── settings.py
    │   ├── signals/
    │   │   ├── __init__.py
    │   │   └── handlers.py
    │   ├── static/
    │   │   ├── js/
    │   │   │   └── colours.js
    │   │   └── paperless.css
    │   ├── templates/
    │   │   ├── admin/
    │   │   │   ├── base_site.html
    │   │   │   ├── documents/
    │   │   │   │   └── document/
    │   │   │   │       ├── change_form.html
    │   │   │   │       ├── change_list.html
    │   │   │   │       ├── change_list_results.html
    │   │   │   │       └── select_object.html
    │   │   │   └── index.html
    │   │   └── documents/
    │   │       └── index.html
    │   ├── templatetags/
    │   │   ├── __init__.py
    │   │   ├── customisation.py
    │   │   └── hacks.py
    │   ├── tests/
    │   │   ├── __init__.py
    │   │   ├── factories.py
    │   │   ├── samples/
    │   │   │   ├── inline_mail.txt
    │   │   │   └── mail.txt
    │   │   ├── test_checks.py
    │   │   ├── test_consumer.py
    │   │   ├── test_document_model.py
    │   │   ├── test_file_handling.py
    │   │   ├── test_importer.py
    │   │   ├── test_logger.py
    │   │   ├── test_mail.py
    │   │   ├── test_matchables.py
    │   │   └── test_models.py
    │   └── views.py
    ├── manage.py
    ├── paperless/
    │   ├── __init__.py
    │   ├── checks.py
    │   ├── db.py
    │   ├── middleware.py
    │   ├── mixins.py
    │   ├── models.py
    │   ├── settings.py
    │   ├── urls.py
    │   ├── version.py
    │   ├── views.py
    │   └── wsgi.py
    ├── paperless_tesseract/
    │   ├── __init__.py
    │   ├── apps.py
    │   ├── languages.py
    │   ├── parsers.py
    │   ├── signals.py
    │   └── tests/
    │       ├── __init__.py
    │       ├── test_date.py
    │       ├── test_ocr.py
    │       └── test_signals.py
    ├── paperless_text/
    │   ├── __init__.py
    │   ├── apps.py
    │   ├── parsers.py
    │   └── signals.py
    ├── reminders/
    │   ├── __init__.py
    │   ├── admin.py
    │   ├── apps.py
    │   ├── filters.py
    │   ├── migrations/
    │   │   ├── 0001_initial.py
    │   │   ├── 0002_auto_20181007_1420.py
    │   │   └── __init__.py
    │   ├── models.py
    │   ├── serialisers.py
    │   ├── tests.py
    │   └── views.py
    ├── setup.cfg
    └── tox.ini
Download .txt
SYMBOL INDEX (638 symbols across 96 files)

FILE: docs/conf.py
  function setup (line 23) | def setup(app):

FILE: management/commands/create_superuser_with_password.py
  class Command (line 5) | class Command(createsuperuser.Command):
    method add_arguments (line 8) | def add_arguments(self, parser):
    method handle (line 19) | def handle(self, *args, **options):

FILE: presentation/js/reveal.js
  function initialize (line 223) | function initialize( options ) {
  function checkCapabilities (line 275) | function checkCapabilities() {
  function load (line 307) | function load() {
  function start (line 368) | function start() {
  function setupDOM (line 424) | function setupDOM() {
  function createStatusDiv (line 471) | function createStatusDiv() {
  function setupPDF (line 494) | function setupPDF() {
  function createSingletonNode (line 564) | function createSingletonNode( container, tagname, classname, innerHTML ) {
  function createBackgrounds (line 595) | function createBackgrounds() {
  function createBackground (line 662) | function createBackground( slide, container ) {
  function setupPostMessage (line 753) | function setupPostMessage() {
  function configure (line 777) | function configure( options ) {
  function addEventListeners (line 874) | function addEventListeners() {
  function removeEventListeners (line 952) | function removeEventListeners() {
  function extend (line 997) | function extend( a, b ) {
  function toArray (line 1008) | function toArray( o ) {
  function deserialize (line 1017) | function deserialize( value ) {
  function distanceBetween (line 1037) | function distanceBetween( a, b ) {
  function transformElement (line 1049) | function transformElement( element, transform ) {
  function injectStyleSheet (line 1062) | function injectStyleSheet( value ) {
  function colorToRgb (line 1085) | function colorToRgb( color ) {
  function colorBrightness (line 1135) | function colorBrightness( color ) {
  function getAbsoluteHeight (line 1151) | function getAbsoluteHeight( element ) {
  function getRemainingHeight (line 1188) | function getRemainingHeight( element, height ) {
  function isPrintingPDF (line 1213) | function isPrintingPDF() {
  function hideAddressBar (line 1222) | function hideAddressBar() {
  function removeAddressBar (line 1236) | function removeAddressBar() {
  function dispatchEvent (line 1248) | function dispatchEvent( type, args ) {
  function enableRollingLinks (line 1266) | function enableRollingLinks() {
  function disableRollingLinks (line 1291) | function disableRollingLinks() {
  function enablePreviewLinks (line 1310) | function enablePreviewLinks( selector ) {
  function disablePreviewLinks (line 1325) | function disablePreviewLinks() {
  function showPreview (line 1340) | function showPreview( url ) {
  function showHelp (line 1382) | function showHelp() {
  function closeOverlay (line 1427) | function closeOverlay() {
  function layout (line 1440) | function layout() {
  function layoutSlideContents (line 1523) | function layoutSlideContents( width, height, padding ) {
  function getComputedSlideSize (line 1556) | function getComputedSlideSize( presentationWidth, presentationHeight ) {
  function setPreviousVerticalIndex (line 1594) | function setPreviousVerticalIndex( stack, v ) {
  function getPreviousVerticalIndex (line 1609) | function getPreviousVerticalIndex( stack ) {
  function activateOverview (line 1629) | function activateOverview() {
  function deactivateOverview (line 1705) | function deactivateOverview() {
  function toggleOverview (line 1750) | function toggleOverview( override ) {
  function isOverview (line 1767) | function isOverview() {
  function isVerticalSlide (line 1780) | function isVerticalSlide( slide ) {
  function enterFullscreen (line 1795) | function enterFullscreen() {
  function pause (line 1816) | function pause() {
  function resume (line 1834) | function resume() {
  function togglePause (line 1850) | function togglePause( override ) {
  function isPaused (line 1864) | function isPaused() {
  function toggleAutoSlide (line 1877) | function toggleAutoSlide( override ) {
  function isAutoSliding (line 1892) | function isAutoSliding() {
  function slide (line 1909) | function slide( h, v, f, o ) {
  function sync (line 2053) | function sync() {
  function resetVerticalSlides (line 2090) | function resetVerticalSlides() {
  function sortAllFragments (line 2115) | function sortAllFragments() {
  function updateSlides (line 2146) | function updateSlides( selector, index ) {
  function updateSlidesVisibility (line 2252) | function updateSlidesVisibility() {
  function updateProgress (line 2321) | function updateProgress() {
  function updateSlideNumber (line 2335) | function updateSlideNumber() {
  function updateControls (line 2354) | function updateControls() {
  function updateBackground (line 2408) | function updateBackground( includeAll ) {
  function updateParallax (line 2515) | function updateParallax() {
  function showSlide (line 2552) | function showSlide( slide ) {
  function hideSlide (line 2630) | function hideSlide( slide ) {
  function availableRoutes (line 2649) | function availableRoutes() {
  function availableFragments (line 2678) | function availableFragments() {
  function formatEmbeddedContent (line 2698) | function formatEmbeddedContent() {
  function startEmbeddedContent (line 2722) | function startEmbeddedContent( slide ) {
  function stopEmbeddedContent (line 2758) | function stopEmbeddedContent( slide ) {
  function getProgress (line 2794) | function getProgress() {
  function isSpeakerNotes (line 2858) | function isSpeakerNotes() {
  function readURL (line 2867) | function readURL() {
  function writeURL (line 2915) | function writeURL( delay ) {
  function getIndices (line 2962) | function getIndices( slide ) {
  function getTotalSlides (line 3009) | function getTotalSlides() {
  function getSlide (line 3018) | function getSlide( x, y ) {
  function getSlideBackground (line 3037) | function getSlideBackground( x, y ) {
  function getState (line 3069) | function getState() {
  function setState (line 3088) | function setState( state ) {
  function sortFragments (line 3121) | function sortFragments( fragments ) {
  function navigateFragment (line 3179) | function navigateFragment( index, offset ) {
  function nextFragment (line 3262) | function nextFragment() {
  function previousFragment (line 3274) | function previousFragment() {
  function cueAutoSlide (line 3283) | function cueAutoSlide() {
  function cancelAutoSlide (line 3346) | function cancelAutoSlide() {
  function pauseAutoSlide (line 3353) | function pauseAutoSlide() {
  function resumeAutoSlide (line 3367) | function resumeAutoSlide() {
  function navigateLeft (line 3377) | function navigateLeft() {
  function navigateRight (line 3392) | function navigateRight() {
  function navigateUp (line 3407) | function navigateUp() {
  function navigateDown (line 3416) | function navigateDown() {
  function navigatePrev (line 3431) | function navigatePrev() {
  function navigateNext (line 3462) | function navigateNext() {
  function onUserInput (line 3492) | function onUserInput( event ) {
  function onDocumentKeyPress (line 3503) | function onDocumentKeyPress( event ) {
  function onDocumentKeyDown (line 3520) | function onDocumentKeyDown( event ) {
  function onTouchStart (line 3642) | function onTouchStart( event ) {
  function onTouchMove (line 3665) | function onTouchMove( event ) {
  function onTouchEnd (line 3752) | function onTouchEnd( event ) {
  function onPointerDown (line 3761) | function onPointerDown( event ) {
  function onPointerMove (line 3773) | function onPointerMove( event ) {
  function onPointerUp (line 3785) | function onPointerUp( event ) {
  function onDocumentMouseScroll (line 3798) | function onDocumentMouseScroll( event ) {
  function onProgressClicked (line 3822) | function onProgressClicked( event ) {
  function onNavigateLeftClicked (line 3838) | function onNavigateLeftClicked( event ) { event.preventDefault(); onUser...
  function onNavigateRightClicked (line 3839) | function onNavigateRightClicked( event ) { event.preventDefault(); onUse...
  function onNavigateUpClicked (line 3840) | function onNavigateUpClicked( event ) { event.preventDefault(); onUserIn...
  function onNavigateDownClicked (line 3841) | function onNavigateDownClicked( event ) { event.preventDefault(); onUser...
  function onNavigatePrevClicked (line 3842) | function onNavigatePrevClicked( event ) { event.preventDefault(); onUser...
  function onNavigateNextClicked (line 3843) | function onNavigateNextClicked( event ) { event.preventDefault(); onUser...
  function onWindowHashChange (line 3848) | function onWindowHashChange( event ) {
  function onWindowResize (line 3857) | function onWindowResize( event ) {
  function onPageVisibilityChange (line 3866) | function onPageVisibilityChange( event ) {
  function onOverviewSlideClicked (line 3884) | function onOverviewSlideClicked( event ) {
  function onPreviewLinkClicked (line 3917) | function onPreviewLinkClicked( event ) {
  function onAutoSlidePlayerClick (line 3932) | function onAutoSlidePlayerClick( event ) {
  function Playback (line 3966) | function Playback( container, progressCheck ) {

FILE: presentation/plugin/highlight/highlight.js
  function j (line 30) | function j(v){return v.replace(/&/gm,"&amp;").replace(/</gm,"&lt;").repl...
  function t (line 30) | function t(v){return v.nodeName.toLowerCase()}
  function h (line 30) | function h(w,x){var v=w&&w.exec(x);return v&&v.index==0}
  function r (line 30) | function r(w){var v=(w.className+" "+(w.parentNode?w.parentNode.classNam...
  function o (line 30) | function o(x,y){var v={};for(var w in x){v[w]=x[w]}if(y){for(var w in y)...
  function u (line 30) | function u(x){var v=[];(function w(y,z){for(var A=y.firstChild;A;A=A.nex...
  function q (line 30) | function q(w,y,C){var x=0;var F="";var z=[];function B(){if(!w.length||!...
  function m (line 30) | function m(y){function v(z){return(z&&z.source)||z}function w(A,z){retur...
  function c (line 30) | function c(T,L,J,R){function v(V,W){for(var U=0;U<W.c.length;U++){if(h(W...
  function e (line 30) | function e(y,x){x=x||b.languages||Object.keys(f);var v={r:0,value:j(y)};...
  function g (line 30) | function g(v){if(b.tabReplace){v=v.replace(/^((<[^>]+>|\t)+)/gm,function...
  function p (line 30) | function p(A){var B=r(A);if(/no(-?)highlight/.test(B)){return}var y;if(b...
  function s (line 30) | function s(v){b=o(b,v)}
  function l (line 30) | function l(){if(l.called){return}l.called=true;var v=document.querySelec...
  function a (line 30) | function a(){addEventListener("DOMContentLoaded",l,false);addEventListen...
  function d (line 30) | function d(v,x){var w=f[v]=x(this);if(w.aliases){w.aliases.forEach(funct...
  function k (line 30) | function k(){return Object.keys(f)}
  function i (line 30) | function i(v){return f[v]||f[n[v]]}

FILE: presentation/plugin/leap/leap.js
  function i (line 15) | function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&re...
  function indexOf (line 15) | function indexOf(xs,x){if(xs.indexOf)return xs.indexOf(x);for(var i=0;i<...

FILE: presentation/plugin/markdown/markdown.js
  function getMarkdownFromSlide (line 39) | function getMarkdownFromSlide( section ) {
  function getForwardedAttributes (line 66) | function getForwardedAttributes( section ) {
  function getSlidifyOptions (line 94) | function getSlidifyOptions( options ) {
  function createMarkdownSlide (line 108) | function createMarkdownSlide( content, options ) {
  function slidify (line 126) | function slidify( markdown, options ) {
  function processSlides (line 199) | function processSlides() {
  function addAttributeInElement (line 281) | function addAttributeInElement( node, elementTarget, separator ) {
  function addAttributes (line 303) | function addAttributes( section, element, previousElement, separatorElem...
  function convertSlides (line 342) | function convertSlides() {

FILE: presentation/plugin/markdown/marked.js
  function Lexer (line 10) | function Lexer(options){this.tokens=[];this.tokens.links={};this.options...
  function InlineLexer (line 21) | function InlineLexer(links,options){this.options=options||marked.default...
  function Parser (line 27) | function Parser(options){this.tokens=[];this.token=null;
  function escape (line 33) | function escape(html,encode){return html.replace(!encode?/&(?!#?\w+;)/g:...
  function replace (line 33) | function replace(regex,opt){regex=regex.source;opt=opt||"";return functi...
  function noop (line 33) | function noop(){}
  function merge (line 33) | function merge(obj){var i=
  function marked (line 34) | function marked(src,opt,callback){if(callback||typeof opt==="function"){...

FILE: presentation/plugin/math/math.js
  function loadScript (line 35) | function loadScript( url, callback ) {

FILE: presentation/plugin/notes-server/client.js
  function post (line 16) | function post() {

FILE: presentation/plugin/notes/notes.js
  function openNotes (line 14) | function openNotes() {

FILE: presentation/plugin/search/search.js
  function Hilitor (line 19) | function Hilitor(id, tag)
  function openSearch (line 111) | function openSearch() {
  function toggleSearch (line 119) | function toggleSearch() {
  function doSearch (line 130) | function doSearch() {

FILE: presentation/plugin/zoom-js/zoom.js
  function magnify (line 88) | function magnify( rect, scale ) {
  function pan (line 164) | function pan() {
  function getScrollOffset (line 189) | function getScrollOffset() {

FILE: src/documents/actions.py
  function select_action (line 10) | def select_action(
  function simple_action (line 62) | def simple_action(
  function add_tag_to_selected (line 86) | def add_tag_to_selected(modeladmin, request, queryset):
  function remove_tag_from_selected (line 100) | def remove_tag_from_selected(modeladmin, request, queryset):
  function set_correspondent_on_selected (line 114) | def set_correspondent_on_selected(modeladmin, request, queryset):
  function remove_correspondent_from_selected (line 129) | def remove_correspondent_from_selected(modeladmin, request, queryset):

FILE: src/documents/admin.py
  class FinancialYearFilter (line 26) | class FinancialYearFilter(admin.SimpleListFilter):
    method _fy_start (line 32) | def _fy_start(self, year):
    method _fy_end (line 37) | def _fy_end(self, year):
    method _fy_does_wrap (line 42) | def _fy_does_wrap(self):
    method _determine_fy (line 53) | def _determine_fy(self, date):
    method lookups (line 72) | def lookups(self, request, model_admin):
    method queryset (line 82) | def queryset(self, request, queryset):
  class RecentCorrespondentFilter (line 91) | class RecentCorrespondentFilter(admin.RelatedFieldListFilter):
    method field_choices (line 97) | def field_choices(self, field, request, model_admin):
  class CommonAdmin (line 112) | class CommonAdmin(admin.ModelAdmin):
  class CorrespondentAdmin (line 116) | class CorrespondentAdmin(CommonAdmin):
    method get_queryset (line 130) | def get_queryset(self, request):
    method document_count (line 138) | def document_count(self, obj):
    method last_correspondence (line 142) | def last_correspondence(self, obj):
  class TagAdmin (line 147) | class TagAdmin(CommonAdmin):
    class Media (line 156) | class Media:
    method get_queryset (line 159) | def get_queryset(self, request):
    method document_count (line 164) | def document_count(self, obj):
  class DocumentAdmin (line 169) | class DocumentAdmin(DjangoQLSearchMixin, CommonAdmin):
    class Media (line 171) | class Media:
    method __init__ (line 199) | def __init__(self, *args, **kwargs):
    method has_add_permission (line 203) | def has_add_permission(self, request):
    method created_ (line 206) | def created_(self, obj):
    method changelist_view (line 210) | def changelist_view(self, request, extra_context=None):
    method change_view (line 223) | def change_view(self, request, object_id=None, form_url='',
    method response_change (line 245) | def response_change(self, request, obj):
    method thumbnail (line 283) | def thumbnail(self, obj):
    method tags_ (line 297) | def tags_(self, obj):
    method document (line 316) | def document(self, obj):
    method _html_tag (line 332) | def _html_tag(kind, inside=None, **kwargs):
  class LogAdmin (line 342) | class LogAdmin(CommonAdmin):

FILE: src/documents/apps.py
  class DocumentsConfig (line 5) | class DocumentsConfig(AppConfig):
    method ready (line 9) | def ready(self):

FILE: src/documents/checks.py
  function changed_password_check (line 9) | def changed_password_check(app_configs, **kwargs):

FILE: src/documents/consumer.py
  class ConsumerError (line 24) | class ConsumerError(Exception):
  class Consumer (line 28) | class Consumer:
    method __init__ (line 42) | def __init__(self, consume=settings.CONSUMPTION_DIR,
    method log (line 78) | def log(self, level, message):
    method consume_new_files (line 83) | def consume_new_files(self):
    method try_consume_file (line 121) | def try_consume_file(self, file):
    method _get_parser_class (line 185) | def _get_parser_class(self, doc):
    method _store (line 210) | def _store(self, text, doc, thumbnail, date):
    method _write (line 253) | def _write(self, document, source, target):
    method _cleanup_doc (line 262) | def _cleanup_doc(self, doc):
    method _is_duplicate (line 267) | def _is_duplicate(doc):

FILE: src/documents/filters.py
  class CorrespondentFilterSet (line 12) | class CorrespondentFilterSet(FilterSet):
    class Meta (line 14) | class Meta:
  class TagFilterSet (line 25) | class TagFilterSet(FilterSet):
    class Meta (line 27) | class Meta:
  class DocumentFilterSet (line 38) | class DocumentFilterSet(FilterSet):
    class Meta (line 47) | class Meta:

FILE: src/documents/forms.py
  class UploadForm (line 13) | class UploadForm(forms.Form):
    method __init__ (line 33) | def __init__(self, *args, **kwargs):
    method clean_correspondent (line 37) | def clean_correspondent(self):
    method clean_title (line 55) | def clean_title(self):
    method clean_document (line 67) | def clean_document(self):
    method save (line 81) | def save(self):

FILE: src/documents/loggers.py
  class PaperlessLogger (line 4) | class PaperlessLogger(logging.StreamHandler):
    method emit (line 10) | def emit(self, record):

FILE: src/documents/mail.py
  class MailFetcherError (line 19) | class MailFetcherError(Exception):
  class InvalidMessageError (line 23) | class InvalidMessageError(MailFetcherError):
  class Loggable (line 27) | class Loggable(object):
    method __init__ (line 29) | def __init__(self, group=None):
    method log (line 33) | def log(self, level, message):
  class Message (line 39) | class Message(Loggable):
    method __init__ (line 47) | def __init__(self, data, group=None):
    method __bool__ (line 102) | def __bool__(self):
    method check_subject (line 105) | def check_subject(self):
    method check_body (line 112) | def check_body(self):
    method _set_time (line 116) | def _set_time(self, message):
    method file_name (line 126) | def file_name(self):
  class Attachment (line 130) | class Attachment(object):
    method __init__ (line 135) | def __init__(self, data, content_type):
    method read (line 147) | def read(self):
  class MailFetcher (line 151) | class MailFetcher(Loggable):
    method __init__ (line 153) | def __init__(self, consume=settings.CONSUMPTION_DIR):
    method pull (line 171) | def pull(self):
    method _get_messages (line 197) | def _get_messages(self):
    method _connect (line 218) | def _connect(self):
    method _login (line 225) | def _login(self):
    method _fetch (line 235) | def _fetch(self):

FILE: src/documents/management/commands/change_storage_type.py
  class Command (line 11) | class Command(BaseCommand):
    method add_arguments (line 18) | def add_arguments(self, parser):
    method handle (line 36) | def handle(self, *args, **options):
    method __gpg_to_unencrypted (line 71) | def __gpg_to_unencrypted(passphrase):
    method __unencrypted_to_gpg (line 99) | def __unencrypted_to_gpg(passphrase):

FILE: src/documents/management/commands/document_consumer.py
  class Command (line 17) | class Command(BaseCommand):
    method __init__ (line 26) | def __init__(self, *args, **kwargs):
    method add_arguments (line 37) | def add_arguments(self, parser):
    method handle (line 68) | def handle(self, *args, **options):
    method loop (line 103) | def loop(self, loop_time, mail_delta):
    method loop_step (line 112) | def loop_step(self, mail_delta, time_now=None):
    method loop_inotify (line 124) | def loop_inotify(self, mail_delta):

FILE: src/documents/management/commands/document_correspondents.py
  class Command (line 10) | class Command(Renderable, BaseCommand):
    method __init__ (line 26) | def __init__(self, *args, **kwargs):
    method add_arguments (line 30) | def add_arguments(self, parser):
    method handle (line 40) | def handle(self, *args, **options):

FILE: src/documents/management/commands/document_exporter.py
  class Command (line 16) | class Command(Renderable, BaseCommand):
    method add_arguments (line 24) | def add_arguments(self, parser):
    method __init__ (line 34) | def __init__(self, *args, **kwargs):
    method handle (line 38) | def handle(self, *args, **options):
    method dump (line 53) | def dump(self):
    method dump_legacy (line 102) | def dump_legacy(self):
    method _get_legacy_file_name (line 117) | def _get_legacy_file_name(doc):

FILE: src/documents/management/commands/document_importer.py
  class Command (line 17) | class Command(Renderable, BaseCommand):
    method add_arguments (line 24) | def add_arguments(self, parser):
    method __init__ (line 27) | def __init__(self, *args, **kwargs):
    method handle (line 32) | def handle(self, *args, **options):
    method _check_manifest_exists (line 56) | def _check_manifest_exists(path):
    method _check_manifest (line 63) | def _check_manifest(self):
    method _import_files_from_manifest (line 83) | def _import_files_from_manifest(self):

FILE: src/documents/management/commands/document_logs.py
  class Command (line 6) | class Command(BaseCommand):
    method handle (line 10) | def handle(self, *args, **options):

FILE: src/documents/management/commands/document_renamer.py
  class Command (line 8) | class Command(Renderable, BaseCommand):
    method __init__ (line 14) | def __init__(self, *args, **kwargs):
    method handle (line 18) | def handle(self, *args, **options):

FILE: src/documents/management/commands/document_retagger.py
  class Command (line 8) | class Command(Renderable, BaseCommand):
    method __init__ (line 17) | def __init__(self, *args, **kwargs):
    method handle (line 21) | def handle(self, *args, **options):

FILE: src/documents/management/commands/loaddata_stdin.py
  class Command (line 6) | class Command(LoadDataCommand):
    method parse_name (line 12) | def parse_name(self, fixture_name):
    method find_fixtures (line 17) | def find_fixtures(self, fixture_label):

FILE: src/documents/managers.py
  class GroupConcat (line 7) | class GroupConcat(models.Aggregate):
    method __init__ (line 23) | def __init__(self, expression, separator="\n", **extra):
    method _get_engine (line 36) | def _get_engine(self):
    method _get_function (line 46) | def _get_function(self):
    method _get_template (line 51) | def _get_template(self, separator):
  class LogQuerySet (line 58) | class LogQuerySet(models.query.QuerySet):
    method by_group (line 60) | def by_group(self):
  class LogManager (line 67) | class LogManager(models.Manager):
    method get_queryset (line 69) | def get_queryset(self):

FILE: src/documents/migrations/0001_initial.py
  class Migration (line 9) | class Migration(migrations.Migration):

FILE: src/documents/migrations/0002_auto_20151226_1316.py
  class Migration (line 9) | class Migration(migrations.Migration):

FILE: src/documents/migrations/0003_sender.py
  function move_sender_strings_to_sender_model (line 14) | def move_sender_strings_to_sender_model(apps, schema_editor):
  function realign_senders (line 28) | def realign_senders(apps, schema_editor):
  class Migration (line 34) | class Migration(migrations.Migration):

FILE: src/documents/migrations/0004_auto_20160114_1844.py
  class Migration (line 9) | class Migration(migrations.Migration):

FILE: src/documents/migrations/0005_auto_20160123_0313.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/documents/migrations/0006_auto_20160123_0430.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/documents/migrations/0007_auto_20160126_2114.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/documents/migrations/0008_document_file_type.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/documents/migrations/0009_auto_20160214_0040.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/documents/migrations/0010_log.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/documents/migrations/0011_auto_20160303_1929.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/documents/migrations/0012_auto_20160305_0040.py
  class GnuPG (line 17) | class GnuPG(object):
    method decrypted (line 25) | def decrypted(cls, file_handle):
    method encrypted (line 30) | def encrypted(cls, file_handle):
  function move_documents_and_create_thumbnails (line 39) | def move_documents_and_create_thumbnails(apps, schema_editor):
  class Migration (line 114) | class Migration(migrations.Migration):

FILE: src/documents/migrations/0013_auto_20160325_2111.py
  class Migration (line 9) | class Migration(migrations.Migration):

FILE: src/documents/migrations/0014_document_checksum.py
  class GnuPG (line 16) | class GnuPG(object):
    method decrypted (line 24) | def decrypted(cls, file_handle):
    method encrypted (line 29) | def encrypted(cls, file_handle):
  class Document (line 38) | class Document(object):
    method __init__ (line 45) | def __init__(self, doc):
    method __str__ (line 53) | def __str__(self):
    method source_path (line 63) | def source_path(self):
    method source_file (line 72) | def source_file(self):
    method file_name (line 76) | def file_name(self):
  function set_checksums (line 80) | def set_checksums(apps, schema_editor):
  function do_nothing (line 126) | def do_nothing(apps, schema_editor):
  class Migration (line 130) | class Migration(migrations.Migration):

FILE: src/documents/migrations/0015_add_insensitive_to_match.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/documents/migrations/0016_auto_20170325_1558.py
  class Migration (line 9) | class Migration(migrations.Migration):

FILE: src/documents/migrations/0017_auto_20170512_0507.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/documents/migrations/0018_auto_20170715_1712.py
  class Migration (line 9) | class Migration(migrations.Migration):

FILE: src/documents/migrations/0019_add_consumer_user.py
  function forwards_func (line 9) | def forwards_func(apps, schema_editor):
  function reverse_func (line 13) | def reverse_func(apps, schema_editor):
  class Migration (line 17) | class Migration(migrations.Migration):

FILE: src/documents/migrations/0020_document_added.py
  function set_added_time_to_created_time (line 8) | def set_added_time_to_created_time(apps, schema_editor):
  class Migration (line 15) | class Migration(migrations.Migration):

FILE: src/documents/migrations/0021_document_storage_type.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/documents/migrations/0022_auto_20181007_1420.py
  function re_slug_all_the_things (line 7) | def re_slug_all_the_things(apps, schema_editor):
  class Migration (line 25) | class Migration(migrations.Migration):

FILE: src/documents/migrations/0023_document_current_filename.py
  function set_filename (line 6) | def set_filename(apps, schema_editor):
  class Migration (line 20) | class Migration(migrations.Migration):

FILE: src/documents/mixins.py
  class Renderable (line 1) | class Renderable:
    method _render (line 7) | def _render(self, text, verbosity):

FILE: src/documents/models.py
  class MatchingModel (line 27) | class MatchingModel(models.Model):
    class Meta (line 66) | class Meta:
    method __str__ (line 70) | def __str__(self):
    method conditions (line 74) | def conditions(self):
    method match_all (line 79) | def match_all(cls, text, tags=None):
    method matches (line 89) | def matches(self, text):
    method _split_match (line 133) | def _split_match(self):
    method save (line 150) | def save(self, *args, **kwargs):
  class Correspondent (line 158) | class Correspondent(MatchingModel):
    class Meta (line 164) | class Meta:
  class Tag (line 168) | class Tag(MatchingModel):
  class Document (line 189) | class Document(models.Model):
    class Meta (line 267) | class Meta:
    method __str__ (line 270) | def __str__(self):
    method find_renamed_document (line 279) | def find_renamed_document(self, subdirectory=""):
    method source_filename (line 305) | def source_filename(self):
    method many_to_dictionary (line 332) | def many_to_dictionary(field):
    method generate_source_filename (line 357) | def generate_source_filename(self):
    method create_source_directory (line 383) | def create_source_directory(self):
    method source_path (line 393) | def source_path(self):
    method filename_to_path (line 397) | def filename_to_path(filename):
    method source_file (line 406) | def source_file(self):
    method file_name (line 410) | def file_name(self):
    method download_url (line 414) | def download_url(self):
    method thumbnail_path (line 418) | def thumbnail_path(self):
    method thumbnail_file (line 432) | def thumbnail_file(self):
    method thumbnail_url (line 436) | def thumbnail_url(self):
    method set_filename (line 439) | def set_filename(self, filename):
    method try_delete_empty_directories (line 444) | def try_delete_empty_directories(directory):
    method delete_all_empty_subdirectories (line 462) | def delete_all_empty_subdirectories(directory):
  function update_filename (line 487) | def update_filename(sender, instance, **kwargs):
  function delete_files (line 539) | def delete_files(sender, instance, **kwargs):
  class Log (line 559) | class Log(models.Model):
    class Meta (line 577) | class Meta:
    method __str__ (line 580) | def __str__(self):
    method save (line 583) | def save(self, *args, **kwargs):
  class FileInfo (line 597) | class FileInfo:
    method __init__ (line 662) | def __init__(self, created=None, correspondent=None, title=None, tags=(),
    method _get_created (line 672) | def _get_created(cls, created):
    method _get_correspondent (line 679) | def _get_correspondent(cls, name):
    method _get_title (line 687) | def _get_title(cls, title):
    method _get_tags (line 691) | def _get_tags(cls, tags):
    method _get_extension (line 701) | def _get_extension(cls, extension):
    method _mangle_property (line 710) | def _mangle_property(cls, properties, name):
    method from_path (line 717) | def from_path(cls, path):

FILE: src/documents/parsers.py
  class ParseError (line 32) | class ParseError(Exception):
  class DocumentParser (line 36) | class DocumentParser:
    method __init__ (line 42) | def __init__(self, path):
    method get_thumbnail (line 49) | def get_thumbnail(self):
    method optimise_thumbnail (line 55) | def optimise_thumbnail(self, in_path):
    method get_optimised_thumbnail (line 65) | def get_optimised_thumbnail(self):
    method get_text (line 68) | def get_text(self):
    method get_date (line 74) | def get_date(self):
    method log (line 155) | def log(self, level, message):
    method cleanup (line 160) | def cleanup(self):

FILE: src/documents/serialisers.py
  class CorrespondentSerializer (line 6) | class CorrespondentSerializer(serializers.HyperlinkedModelSerializer):
    class Meta (line 8) | class Meta:
  class TagSerializer (line 20) | class TagSerializer(serializers.HyperlinkedModelSerializer):
    class Meta (line 22) | class Meta:
  class CorrespondentField (line 35) | class CorrespondentField(serializers.HyperlinkedRelatedField):
    method get_queryset (line 36) | def get_queryset(self):
  class TagsField (line 40) | class TagsField(serializers.HyperlinkedRelatedField):
    method get_queryset (line 41) | def get_queryset(self):
  class DocumentSerializer (line 45) | class DocumentSerializer(serializers.ModelSerializer):
    class Meta (line 51) | class Meta:
  class LogSerializer (line 70) | class LogSerializer(serializers.ModelSerializer):
    class Meta (line 75) | class Meta:

FILE: src/documents/signals/handlers.py
  function logger (line 14) | def logger(message, group):
  function set_correspondent (line 18) | def set_correspondent(sender, document=None, logging_group=None, **kwargs):
  function set_tags (line 47) | def set_tags(sender, document=None, logging_group=None, **kwargs):
  function run_pre_consume_script (line 64) | def run_pre_consume_script(sender, filename, **kwargs):
  function run_post_consume_script (line 72) | def run_post_consume_script(sender, document, **kwargs):
  function cleanup_document_deletion (line 90) | def cleanup_document_deletion(sender, instance, using, **kwargs):
  function set_log_entry (line 102) | def set_log_entry(sender, document=None, logging_group=None, **kwargs):

FILE: src/documents/templatetags/customisation.py
  function custom_css (line 11) | def custom_css():
  function custom_js (line 26) | def custom_js():

FILE: src/documents/templatetags/hacks.py
  function result_list (line 17) | def result_list(cl):
  function add_doc_edit_url (line 35) | def add_doc_edit_url(result):

FILE: src/documents/tests/factories.py
  class CorrespondentFactory (line 6) | class CorrespondentFactory(factory.DjangoModelFactory):
    class Meta (line 8) | class Meta:
  class DocumentFactory (line 14) | class DocumentFactory(factory.DjangoModelFactory):
    class Meta (line 16) | class Meta:

FILE: src/documents/tests/test_checks.py
  class ChecksTestCase (line 10) | class ChecksTestCase(TestCase):
    method test_changed_password_check_empty_db (line 12) | def test_changed_password_check_empty_db(self):
    method test_changed_password_check_no_encryption (line 15) | def test_changed_password_check_no_encryption(self):
    method test_changed_password_check_gpg_encryption_with_good_password (line 20) | def test_changed_password_check_gpg_encryption_with_good_password(self):
    method test_changed_password_check_fail (line 24) | def test_changed_password_check_fail(self):

FILE: src/documents/tests/test_consumer.py
  class TestConsumer (line 14) | class TestConsumer(TestCase):
    method setUp (line 17) | def setUp(self):
    method tearDown (line 41) | def tearDown(self):
    method test_file_consumption (line 52) | def test_file_consumption(self):
    method test_duplicate_file_consumption (line 68) | def test_duplicate_file_consumption(self):
    class DummyParser (line 88) | class DummyParser(object):
    method test__get_parser_class_1_parser (line 91) | def test__get_parser_class_1_parser(self):
    method test__get_parser_class_n_parsers (line 100) | def test__get_parser_class_n_parsers(self, m, *args):
    method test__get_parser_class_0_parsers (line 121) | def test__get_parser_class_0_parsers(self, m, *args):
    method _get_consumer (line 131) | def _get_consumer(self, m, *args):
  class TestAttributes (line 139) | class TestAttributes(TestCase):
    method _test_guess_attributes_from_name (line 148) | def _test_guess_attributes_from_name(self, path, sender, title, tags):
    method test_guess_attributes_from_name0 (line 170) | def test_guess_attributes_from_name0(self):
    method test_guess_attributes_from_name1 (line 174) | def test_guess_attributes_from_name1(self):
    method test_guess_attributes_from_name2 (line 178) | def test_guess_attributes_from_name2(self):
    method test_guess_attributes_from_name3 (line 182) | def test_guess_attributes_from_name3(self):
    method test_guess_attributes_from_name4 (line 186) | def test_guess_attributes_from_name4(self):
    method test_guess_attributes_from_name5 (line 190) | def test_guess_attributes_from_name5(self):
    method test_guess_attributes_from_name6 (line 198) | def test_guess_attributes_from_name6(self):
    method test_guess_attributes_from_name7 (line 206) | def test_guess_attributes_from_name7(self):
    method test_guess_attributes_from_name8 (line 214) | def test_guess_attributes_from_name8(self):
    method test_guess_attributes_from_name9 (line 222) | def test_guess_attributes_from_name9(self):
    method test_guess_attributes_from_name10 (line 230) | def test_guess_attributes_from_name10(self):
    method test_guess_attributes_from_name_when_correspondent_empty (line 238) | def test_guess_attributes_from_name_when_correspondent_empty(self):
    method test_guess_attributes_from_name_when_title_starts_with_dash (line 246) | def test_guess_attributes_from_name_when_title_starts_with_dash(self):
    method test_guess_attributes_from_name_when_title_ends_with_dash (line 254) | def test_guess_attributes_from_name_when_title_ends_with_dash(self):
    method test_guess_attributes_from_name_when_title_is_empty (line 262) | def test_guess_attributes_from_name_when_title_is_empty(self):
    method test_case_insensitive_tag_creation (line 270) | def test_case_insensitive_tag_creation(self):
  class TestFieldPermutations (line 285) | class TestFieldPermutations(TestCase):
    method _test_guessed_attributes (line 302) | def _test_guessed_attributes(self, filename, created=None,
    method test_just_title (line 339) | def test_just_title(self):
    method test_title_and_correspondent (line 347) | def test_title_and_correspondent(self):
    method test_title_and_correspondent_and_tags (line 357) | def test_title_and_correspondent_and_tags(self):
    method test_created_and_correspondent_and_title_and_tags (line 368) | def test_created_and_correspondent_and_title_and_tags(self):
    method test_created_and_correspondent_and_title (line 393) | def test_created_and_correspondent_and_title(self):
    method test_created_and_title (line 416) | def test_created_and_title(self):
    method test_created_and_title_and_tags (line 431) | def test_created_and_title_and_tags(self):
    method test_invalid_date_format (line 448) | def test_invalid_date_format(self):
    method test_filename_parse_transforms (line 453) | def test_filename_parse_transforms(self):

FILE: src/documents/tests/test_document_model.py
  class TestDocument (line 8) | class TestDocument(TestCase):
    method test_file_deletion (line 10) | def test_file_deletion(self):

FILE: src/documents/tests/test_file_handling.py
  class TestDate (line 15) | class TestDate(TestCase):
    method setUp (line 16) | def setUp(self):
    method tearDown (line 25) | def tearDown(self):
    method test_source_filename (line 30) | def test_source_filename(self):
    method test_generate_source_filename (line 42) | def test_generate_source_filename(self):
    method test_file_renaming (line 56) | def test_file_renaming(self):
    method test_file_renaming_missing_permissions (line 98) | def test_file_renaming_missing_permissions(self):
    method test_document_delete (line 132) | def test_document_delete(self):
    method test_document_delete_nofile (line 153) | def test_document_delete_nofile(self):
    method test_directory_not_empty (line 163) | def test_directory_not_empty(self):
    method test_tags_with_underscore (line 193) | def test_tags_with_underscore(self):
    method test_tags_with_dash (line 213) | def test_tags_with_dash(self):
    method test_tags_malformed (line 233) | def test_tags_malformed(self):
    method test_tags_all (line 253) | def test_tags_all(self):
    method test_tags_out_of_bounds_0 (line 272) | def test_tags_out_of_bounds_0(self):
    method test_tags_out_of_bounds_10000000 (line 287) | def test_tags_out_of_bounds_10000000(self):
    method test_tags_out_of_bounds_99 (line 302) | def test_tags_out_of_bounds_99(self):
    method test_nested_directory_cleanup (line 318) | def test_nested_directory_cleanup(self):
    method test_format_none (line 347) | def test_format_none(self):
    method test_document_renamed (line 357) | def test_document_renamed(self):
    method test_document_renamed_encrypted (line 403) | def test_document_renamed_encrypted(self):
    method test_delete_all_empty_subdirectories (line 447) | def test_delete_all_empty_subdirectories(self):
    method test_try_delete_empty_directories (line 467) | def test_try_delete_empty_directories(self):
    method test_document_accidentally_deleted (line 488) | def test_document_accidentally_deleted(self):
    method test_set_filename (line 521) | def test_set_filename(self):

FILE: src/documents/tests/test_importer.py
  class TestImporter (line 9) | class TestImporter(TestCase):
    method __init__ (line 11) | def __init__(self, *args, **kwargs):
    method test_check_manifest_exists (line 14) | def test_check_manifest_exists(self):
    method test_check_manifest (line 19) | def test_check_manifest(self):

FILE: src/documents/tests/test_logger.py
  class TestPaperlessLog (line 11) | class TestPaperlessLog(TestCase):
    method __init__ (line 13) | def __init__(self, *args, **kwargs):
    method test_that_it_saves_at_all (line 18) | def test_that_it_saves_at_all(self):
    method test_groups (line 42) | def test_groups(self):
    method test_groupped_query (line 71) | def test_groupped_query(self):

FILE: src/documents/tests/test_mail.py
  class TestMessage (line 14) | class TestMessage(TestCase):
    method __init__ (line 16) | def __init__(self, *args, **kwargs):
    method test_init (line 27) | def test_init(self):
  class TestInlineMessage (line 48) | class TestInlineMessage(TestCase):
    method __init__ (line 50) | def __init__(self, *args, **kwargs):
    method test_init (line 61) | def test_init(self):
  class TestAttachment (line 82) | class TestAttachment(TestCase):
    method test_init (line 84) | def test_init(self):

FILE: src/documents/tests/test_matchables.py
  class TestMatching (line 11) | class TestMatching(TestCase):
    method _test_matching (line 13) | def _test_matching(self, text, algorithm, true, false):
    method test_match_all (line 31) | def test_match_all(self):
    method test_match_any (line 80) | def test_match_any(self):
    method test_match_literal (line 127) | def test_match_literal(self):
    method test_match_regex (line 166) | def test_match_regex(self):
    method test_match_fuzzy (line 187) | def test_match_fuzzy(self):
  class TestDocumentConsumptionFinishedSignal (line 205) | class TestDocumentConsumptionFinishedSignal(TestCase):
    method setUp (line 211) | def setUp(self):
    method test_tag_applied_any (line 217) | def test_tag_applied_any(self):
    method test_tag_not_applied (line 224) | def test_tag_not_applied(self):
    method test_correspondent_applied (line 231) | def test_correspondent_applied(self):
    method test_correspondent_not_applied (line 241) | def test_correspondent_not_applied(self):
    method test_logentry_created (line 251) | def test_logentry_created(self):

FILE: src/documents/tests/test_models.py
  class CorrespondentTestCase (line 7) | class CorrespondentTestCase(TestCase):
    method test___str__ (line 9) | def test___str__(self):
  class DocumentTestCase (line 15) | class DocumentTestCase(TestCase):
    method test_correspondent_deletion_does_not_cascade (line 17) | def test_correspondent_deletion_does_not_cascade(self):

FILE: src/documents/views.py
  class IndexView (line 35) | class IndexView(TemplateView):
  class FetchView (line 39) | class FetchView(SessionOrBasicAuthMixin, DetailView):
    method render_to_response (line 43) | def render_to_response(self, context, **response_kwargs):
    method _get_raw_data (line 82) | def _get_raw_data(self, file_handle):
  class PushView (line 88) | class PushView(SessionOrBasicAuthMixin, FormView):
    method form_valid (line 95) | def form_valid(self, form):
    method form_invalid (line 99) | def form_invalid(self, form):
  class CorrespondentViewSet (line 103) | class CorrespondentViewSet(ModelViewSet):
  class TagViewSet (line 114) | class TagViewSet(ModelViewSet):
  class DocumentViewSet (line 125) | class DocumentViewSet(RetrieveModelMixin,
  class LogViewSet (line 142) | class LogViewSet(ReadOnlyModelViewSet):

FILE: src/paperless/checks.py
  function paths_check (line 9) | def paths_check(app_configs, **kwargs):
  function binaries_check (line 70) | def binaries_check(app_configs, **kwargs):

FILE: src/paperless/db.py
  class GnuPG (line 6) | class GnuPG:
    method decrypted (line 14) | def decrypted(cls, file_handle, passphrase=None):
    method encrypted (line 22) | def encrypted(cls, file_handle, passphrase=None):

FILE: src/paperless/middleware.py
  class Middleware (line 5) | class Middleware(MiddlewareMixin):
    method process_request (line 13) | def process_request(self, request):

FILE: src/paperless/mixins.py
  class SessionOrBasicAuthMixin (line 6) | class SessionOrBasicAuthMixin(AccessMixin):
    method dispatch (line 16) | def dispatch(self, request, *args, **kwargs):

FILE: src/paperless/models.py
  class User (line 4) | class User:
    method id (line 16) | def id(self):
    method pk (line 20) | def pk(self):

FILE: src/paperless/settings.py
  function __get_boolean (line 27) | def __get_boolean(key, default="NO"):

FILE: src/paperless/views.py
  class StandardPagination (line 8) | class StandardPagination(PageNumberPagination):
  class FaviconView (line 14) | class FaviconView(View):
    method get (line 16) | def get(self, request, *args, **kwargs):

FILE: src/paperless_tesseract/apps.py
  class PaperlessTesseractConfig (line 4) | class PaperlessTesseractConfig(AppConfig):
    method ready (line 8) | def ready(self):

FILE: src/paperless_tesseract/parsers.py
  class OCRError (line 21) | class OCRError(Exception):
  class RasterisedDocumentParser (line 25) | class RasterisedDocumentParser(DocumentParser):
    method __init__ (line 39) | def __init__(self, path):
    method get_thumbnail (line 43) | def get_thumbnail(self):
    method _is_ocred (line 88) | def _is_ocred(self):
    method get_text (line 97) | def get_text(self):
    method _get_greyscale (line 115) | def _get_greyscale(self):
    method _guess_language (line 148) | def _guess_language(self, text):
    method _get_ocr (line 156) | def _get_ocr(self, imgs):
    method _ocr (line 211) | def _ocr(self, imgs, lang):
    method _assemble_ocr_sections (line 228) | def _assemble_ocr_sections(self, imgs, middle, text):
  function run_convert (line 238) | def run_convert(*args):
  function run_unpaper (line 250) | def run_unpaper(args):
  function strip_excess_whitespace (line 258) | def strip_excess_whitespace(text):
  function image_to_string (line 267) | def image_to_string(args):
  function get_text_from_pdf (line 280) | def get_text_from_pdf(pdf_file):

FILE: src/paperless_tesseract/signals.py
  class ConsumerDeclaration (line 6) | class ConsumerDeclaration:
    method handle (line 11) | def handle(cls, sender, **kwargs):
    method test (line 15) | def test(cls, doc):

FILE: src/paperless_tesseract/tests/test_date.py
  class TestDate (line 14) | class TestDate(TestCase):
    method setUp (line 17) | def setUp(self):
    method tearDown (line 23) | def tearDown(self):
    method test_date_format_1 (line 26) | def test_date_format_1(self):
    method test_date_format_2 (line 32) | def test_date_format_2(self):
    method test_date_format_3 (line 38) | def test_date_format_3(self):
    method test_date_format_4 (line 44) | def test_date_format_4(self):
    method test_date_format_5 (line 57) | def test_date_format_5(self):
    method test_date_format_6 (line 73) | def test_date_format_6(self):
    method test_date_format_7 (line 89) | def test_date_format_7(self):
    method test_date_format_8 (line 106) | def test_date_format_8(self):
    method test_date_format_9 (line 129) | def test_date_format_9(self):
    method test_crazy_date_past (line 150) | def test_crazy_date_past(self, *args):
    method test_crazy_date_future (line 159) | def test_crazy_date_future(self, *args):
    method test_crazy_date_with_spaces (line 168) | def test_crazy_date_with_spaces(self, *args):
    method test_filename_date_parse_invalid (line 178) | def test_filename_date_parse_invalid(self, *args):

FILE: src/paperless_tesseract/tests/test_ocr.py
  class FakeTesseract (line 13) | class FakeTesseract(object):
    method can_detect_orientation (line 16) | def can_detect_orientation():
    method detect_orientation (line 20) | def detect_orientation(file_handle, lang):
    method image_to_string (line 24) | def image_to_string(file_handle, lang):
  class FakePyOcr (line 28) | class FakePyOcr(object):
    method get_available_tools (line 31) | def get_available_tools():
  class TestOCR (line 37) | class TestOCR(TestCase):
    method test_strip_excess_whitespace (line 53) | def test_strip_excess_whitespace(self):
    method test_image_to_string_with_text_free_page (line 68) | def test_image_to_string_with_text_free_page(self):

FILE: src/paperless_tesseract/tests/test_signals.py
  class SignalsTestCase (line 6) | class SignalsTestCase(TestCase):
    method test_test_handles_various_file_names_true (line 8) | def test_test_handles_various_file_names_true(self):
    method test_test_handles_various_file_names_false (line 25) | def test_test_handles_various_file_names_false(self):

FILE: src/paperless_text/apps.py
  class PaperlessTextConfig (line 4) | class PaperlessTextConfig(AppConfig):
    method ready (line 8) | def ready(self):

FILE: src/paperless_text/parsers.py
  class TextDocumentParser (line 9) | class TextDocumentParser(DocumentParser):
    method __init__ (line 20) | def __init__(self, path):
    method get_thumbnail (line 24) | def get_thumbnail(self):
    method get_text (line 85) | def get_text(self):
  function run_command (line 96) | def run_command(*args):

FILE: src/paperless_text/signals.py
  class ConsumerDeclaration (line 6) | class ConsumerDeclaration:
    method handle (line 11) | def handle(cls, sender, **kwargs):
    method test (line 15) | def test(cls, doc):

FILE: src/reminders/admin.py
  class ReminderAdmin (line 7) | class ReminderAdmin(admin.ModelAdmin):
    class Media (line 9) | class Media:

FILE: src/reminders/apps.py
  class RemindersConfig (line 4) | class RemindersConfig(AppConfig):

FILE: src/reminders/filters.py
  class ReminderFilterSet (line 6) | class ReminderFilterSet(FilterSet):
    class Meta (line 8) | class Meta(object):

FILE: src/reminders/migrations/0001_initial.py
  class Migration (line 9) | class Migration(migrations.Migration):

FILE: src/reminders/migrations/0002_auto_20181007_1420.py
  class Migration (line 7) | class Migration(migrations.Migration):

FILE: src/reminders/models.py
  class Reminder (line 4) | class Reminder(models.Model):

FILE: src/reminders/serialisers.py
  class ReminderSerializer (line 7) | class ReminderSerializer(serializers.HyperlinkedModelSerializer):
    class Meta (line 12) | class Meta(object):

FILE: src/reminders/views.py
  class ReminderViewSet (line 14) | class ReminderViewSet(ModelViewSet):
Condensed preview — 258 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,256K chars).
[
  {
    "path": ".docker-hub-test",
    "chars": 18,
    "preview": "Docker Hub test 2\n"
  },
  {
    "path": ".editorconfig",
    "chars": 535,
    "preview": "# EditorConfig: http://EditorConfig.org\n\nroot = true\n\n[*]\nindent_style = tab\nindent_size = 2\ninsert_final_newline = true"
  },
  {
    "path": ".gitattributes",
    "chars": 22,
    "preview": "THANKS.md merge=union\n"
  },
  {
    "path": ".gitignore",
    "chars": 1145,
    "preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\n"
  },
  {
    "path": ".travis.yml",
    "chars": 1333,
    "preview": "language: python\n\nbefore_install:\n- sudo apt-get update -qq\n- sudo apt-get install -qq libpoppler-cpp-dev unpaper tesser"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 3219,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
  },
  {
    "path": "Dockerfile",
    "chars": 2273,
    "preview": "FROM alpine:3.12\n\nLABEL maintainer=\"The Paperless Project https://github.com/the-paperless-project/paperless\" \\\n      co"
  },
  {
    "path": "LICENSE",
    "chars": 35142,
    "preview": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free "
  },
  {
    "path": "Pipfile",
    "chars": 764,
    "preview": "[[source]]\nurl = \"https://pypi.python.org/simple\"\nverify_ssl = true\nname = \"pypi\"\n\n[packages]\ndjango = \"<2.1,>=2.0\"\npill"
  },
  {
    "path": "README-de.md",
    "chars": 7542,
    "preview": "[ [en](README.md) | de | [el](README-el.md) ]\n\n![Paperless](https://raw.githubusercontent.com/the-paperless-project/pape"
  },
  {
    "path": "README-el.md",
    "chars": 6713,
    "preview": "[ [en](README.md) | [de](README-de.md) | el ]\n\n![Paperless](https://raw.githubusercontent.com/the-paperless-project/pape"
  },
  {
    "path": "README.md",
    "chars": 9612,
    "preview": "[ en | [de](README-de.md) | [el](README-el.md) ]\n\n![Paperless](https://raw.githubusercontent.com/the-paperless-project/p"
  },
  {
    "path": "THANKS.md",
    "chars": 740,
    "preview": "# Thanks for using Paperless!\n\nWorking on this project has been exhausting, but rewarding at the same time.\nIt's just wo"
  },
  {
    "path": "ci/deploy-docker",
    "chars": 415,
    "preview": "#!/bin/bash\n\nif [ \"${DOCKER_USERNAME}\" == \"\" -o \"${DOCKER_PASSWORD}\" == \"\" ]\nthen\n    exit 0\nfi\n\ndocker login --username"
  },
  {
    "path": "data/.keep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "docker-compose.env.example",
    "chars": 1338,
    "preview": "# Environment variables to set for Paperless\n# Commented out variables will be replaced with a default within Paperless."
  },
  {
    "path": "docker-compose.yml.example",
    "chars": 2153,
    "preview": "version: '2.1'\n\nservices:\n    webserver:\n        build: ./\n        # uncomment the following line to start automatically"
  },
  {
    "path": "docs/Dockerfile",
    "chars": 357,
    "preview": "FROM python:3.5.1\nMAINTAINER Pit Kleyersburg <pitkley@googlemail.com>\n\n# Install Sphinx and Pygments\nRUN pip install Sph"
  },
  {
    "path": "docs/Makefile",
    "chars": 6826,
    "preview": "# Makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS    =\nSPHINXBUILD "
  },
  {
    "path": "docs/_static/.keep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "docs/_static/custom.css",
    "chars": 354,
    "preview": "/* override table width restrictions */\n@media screen and (min-width: 767px) {\n\n  .wy-table-responsive table td {\n    /*"
  },
  {
    "path": "docs/api.rst",
    "chars": 756,
    "preview": ".. _api:\n\nThe REST API\n############\n\nPaperless makes use of the `Django REST Framework`_ standard API interface\nbecause "
  },
  {
    "path": "docs/changelog.rst",
    "chars": 35306,
    "preview": "Changelog\n#########\n\n2.7.0\n=====\n\n* `syntonym`_ submitted a pull request to catch IMAP connection errors `#475`_.\n* `Sté"
  },
  {
    "path": "docs/conf.py",
    "chars": 11186,
    "preview": "# -*- coding: utf-8 -*-\n#\n# Paperless documentation build configuration file, created by\n# sphinx-quickstart on Mon Oct "
  },
  {
    "path": "docs/consumption.rst",
    "chars": 9209,
    "preview": ".. _consumption:\n\nConsumption\n###########\n\nOnce you've got Paperless setup, you need to start feeding documents into it."
  },
  {
    "path": "docs/contributing.rst",
    "chars": 4229,
    "preview": ".. _contributing:\n\nContributing to Paperless\n#########################\n\nMaybe you've been using Paperless for a while an"
  },
  {
    "path": "docs/customising.rst",
    "chars": 1427,
    "preview": ".. _customising:\n\nCustomising Paperless\n#####################\n\nCurrently, the Paperless' interface is just the default D"
  },
  {
    "path": "docs/examples/lxc/lxc-install.sh",
    "chars": 4930,
    "preview": "#!/usr/bin/env bash\n\n# Bash script to install paperless in lxc containter\n# paperless.lan\n#\n# Will set-up paperless, apa"
  },
  {
    "path": "docs/examples/lxc/paperless.conf",
    "chars": 584,
    "preview": "<VirtualHost *:80>\n    ServerName paperless.lan\n\n    Alias /static/ /home/paperless/paperless/static/\n    <Directory /ho"
  },
  {
    "path": "docs/extending.rst",
    "chars": 3532,
    "preview": ".. _extending:\n\nExtending Paperless\n===================\n\nFor the most part, Paperless is monolithic, so extending it is "
  },
  {
    "path": "docs/guesswork.rst",
    "chars": 6099,
    "preview": ".. _guesswork:\n\nGuesswork\n#########\n\nDuring the consumption process, Paperless tries to guess some of the attributes\nof "
  },
  {
    "path": "docs/index.rst",
    "chars": 1141,
    "preview": ".. _index:\n\nPaperless\n=========\n\nPaperless is a simple Django application running in two parts:\na :ref:`consumer <utilit"
  },
  {
    "path": "docs/migrating.rst",
    "chars": 3642,
    "preview": ".. _migrating:\n\nMigrating, Updates, and Backups\n===============================\n\nAs Paperless is still under active deve"
  },
  {
    "path": "docs/requirements.rst",
    "chars": 4055,
    "preview": ".. _requirements:\n\nRequirements\n============\n\nYou need a Linux machine or Unix-like setup (theoretically an Apple machin"
  },
  {
    "path": "docs/requirements.txt",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "docs/scanners.rst",
    "chars": 2955,
    "preview": ".. _scanners:\n\nScanner Recommendations\n=======================\n\nAs Paperless operates by watching a folder for new files"
  },
  {
    "path": "docs/screenshots.rst",
    "chars": 358,
    "preview": ".. _screenshots:\n\nScreenshots\n===========\n\nOnce everything is set-up login to paperless using the web front-end\n\n.. imag"
  },
  {
    "path": "docs/setup.rst",
    "chars": 19736,
    "preview": ".. _setup:\n\nSetup\n=====\n\nPaperless isn't a very complicated app, but there are a few components, so some\nbasic documenta"
  },
  {
    "path": "docs/troubleshooting.rst",
    "chars": 3369,
    "preview": ".. _troubleshooting:\n\nTroubleshooting\n===============\n\n.. _troubleshooting-languagemissing:\n\nConsumer warns ``OCR for XX"
  },
  {
    "path": "docs/utilities.rst",
    "chars": 9040,
    "preview": ".. _utilities:\n\nUtilities\n=========\n\nThere's basically three utilities to Paperless: the webserver, consumer, and\nif nee"
  },
  {
    "path": "management/commands/create_superuser_with_password.py",
    "chars": 1468,
    "preview": "from django.contrib.auth.management.commands import createsuperuser\nfrom django.core.management import CommandError\n\n\ncl"
  },
  {
    "path": "overrides/README.md",
    "chars": 446,
    "preview": "# Customizing Paperless\n\n*See customization\n[documentation](https://paperless.readthedocs.io/en/latest/customising.html)"
  },
  {
    "path": "paperless.conf.example",
    "chars": 12326,
    "preview": "# Sample paperless.conf\n# Copy this file to /etc/paperless.conf and modify it to suit your needs.\n# As this file contain"
  },
  {
    "path": "presentation/README.md",
    "chars": 201,
    "preview": "# Presentation\n\nThis presentation was written with\n[reaveal.js](http://lab.hakim.se/reveal-js/), and requires no special"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/css/font-awesome.css",
    "chars": 28747,
    "preview": "/*!\n *  Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome\n *  License - http://fontawesome.io/lice"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/less/animated.less",
    "chars": 713,
    "preview": "// Animated Icons\n// --------------------------\n\n.@{fa-css-prefix}-spin {\n  -webkit-animation: fa-spin 2s infinite linea"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/less/bordered-pulled.less",
    "chars": 330,
    "preview": "// Bordered & Pulled\n// -------------------------\n\n.@{fa-css-prefix}-border {\n  padding: .2em .25em .15em;\n  border: sol"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/less/core.less",
    "chars": 509,
    "preview": "// Base Class Definition\n// -------------------------\n\n.@{fa-css-prefix} {\n  display: inline-block;\n  font: normal norma"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/less/fixed-width.less",
    "chars": 119,
    "preview": "// Fixed Width Icons\n// -------------------------\n.@{fa-css-prefix}-fw {\n  width: (18em / 14);\n  text-align: center;\n}\n"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/less/font-awesome.less",
    "chars": 465,
    "preview": "/*!\n *  Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome\n *  License - http://fontawesome.io/lice"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/less/icons.less",
    "chars": 37290,
    "preview": "/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen\n   readers do not read off random characters th"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/less/larger.less",
    "chars": 370,
    "preview": "// Icon Sizes\n// -------------------------\n\n/* makes the font 33% larger relative to the icon container */\n.@{fa-css-pre"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/less/list.less",
    "chars": 377,
    "preview": "// List Icons\n// -------------------------\n\n.@{fa-css-prefix}-ul {\n  padding-left: 0;\n  margin-left: @fa-li-width;\n  lis"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/less/mixins.less",
    "chars": 983,
    "preview": "// Mixins\n// --------------------------\n\n.fa-icon() {\n  display: inline-block;\n  font: normal normal normal @fa-font-siz"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/less/path.less",
    "chars": 770,
    "preview": "/* FONT PATH\n * -------------------------- */\n\n@font-face {\n  font-family: 'FontAwesome';\n  src: url('@{fa-font-path}/fo"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/less/rotated-flipped.less",
    "chars": 622,
    "preview": "// Rotated & Flipped Icons\n// -------------------------\n\n.@{fa-css-prefix}-rotate-90  { .fa-icon-rotate(90deg, 1);  }\n.@"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/less/stacked.less",
    "chars": 476,
    "preview": "// Stacked Icons\n// -------------------------\n\n.@{fa-css-prefix}-stack {\n  position: relative;\n  display: inline-block;\n"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/less/variables.less",
    "chars": 16792,
    "preview": "// Variables\n// --------------------------\n\n@fa-font-path:        \"../fonts\";\n@fa-font-size-base:   14px;\n//@fa-font-pat"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/scss/_animated.scss",
    "chars": 715,
    "preview": "// Spinning Icons\n// --------------------------\n\n.#{$fa-css-prefix}-spin {\n  -webkit-animation: fa-spin 2s infinite line"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/scss/_bordered-pulled.scss",
    "chars": 332,
    "preview": "// Bordered & Pulled\n// -------------------------\n\n.#{$fa-css-prefix}-border {\n  padding: .2em .25em .15em;\n  border: so"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/scss/_core.scss",
    "chars": 513,
    "preview": "// Base Class Definition\n// -------------------------\n\n.#{$fa-css-prefix} {\n  display: inline-block;\n  font: normal norm"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/scss/_fixed-width.scss",
    "chars": 120,
    "preview": "// Fixed Width Icons\n// -------------------------\n.#{$fa-css-prefix}-fw {\n  width: (18em / 14);\n  text-align: center;\n}\n"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/scss/_icons.scss",
    "chars": 37883,
    "preview": "/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen\n   readers do not read off random characters th"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/scss/_larger.scss",
    "chars": 375,
    "preview": "// Icon Sizes\n// -------------------------\n\n/* makes the font 33% larger relative to the icon container */\n.#{$fa-css-pr"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/scss/_list.scss",
    "chars": 378,
    "preview": "// List Icons\n// -------------------------\n\n.#{$fa-css-prefix}-ul {\n  padding-left: 0;\n  margin-left: $fa-li-width;\n  li"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/scss/_mixins.scss",
    "chars": 1000,
    "preview": "// Mixins\n// --------------------------\n\n@mixin fa-icon() {\n  display: inline-block;\n  font: normal normal normal #{$fa-"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/scss/_path.scss",
    "chars": 783,
    "preview": "/* FONT PATH\n * -------------------------- */\n\n@font-face {\n  font-family: 'FontAwesome';\n  src: url('#{$fa-font-path}/f"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/scss/_rotated-flipped.scss",
    "chars": 672,
    "preview": "// Rotated & Flipped Icons\n// -------------------------\n\n.#{$fa-css-prefix}-rotate-90  { @include fa-icon-rotate(90deg, "
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/scss/_stacked.scss",
    "chars": 482,
    "preview": "// Stacked Icons\n// -------------------------\n\n.#{$fa-css-prefix}-stack {\n  position: relative;\n  display: inline-block;"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/scss/_variables.scss",
    "chars": 16864,
    "preview": "// Variables\n// --------------------------\n\n$fa-font-path:        \"../fonts\" !default;\n$fa-font-size-base:   14px !defau"
  },
  {
    "path": "presentation/contrib/font-awesome-4.3.0/scss/font-awesome.scss",
    "chars": 405,
    "preview": "/*!\n *  Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome\n *  License - http://fontawesome.io/lice"
  },
  {
    "path": "presentation/contrib/google/css/lato.css",
    "chars": 796,
    "preview": "@font-face {\n  font-family: 'Lato';\n  font-style: normal;\n  font-weight: 400;\n  src: local('Lato Regular'), local('Lato-"
  },
  {
    "path": "presentation/css/print/paper.css",
    "chars": 4861,
    "preview": "/* Default Print Stylesheet Template\n   by Rob Glazebrook of CSSnewbie.com\n   Last Updated: June 4, 2008\n\n   Feel free ("
  },
  {
    "path": "presentation/css/print/pdf.css",
    "chars": 3419,
    "preview": "/* Default Print Stylesheet Template\n   by Rob Glazebrook of CSSnewbie.com\n   Last Updated: June 4, 2008\n\n   Feel free ("
  },
  {
    "path": "presentation/css/reveal.css",
    "chars": 45149,
    "preview": "/*!\n * reveal.js\n * http://lab.hakim.se/reveal-js\n * MIT licensed\n *\n * Copyright (C) 2015 Hakim El Hattab, http://hakim"
  },
  {
    "path": "presentation/css/reveal.scss",
    "chars": 36276,
    "preview": "/*!\n * reveal.js\n * http://lab.hakim.se/reveal-js\n * MIT licensed\n *\n * Copyright (C) 2015 Hakim El Hattab, http://hakim"
  },
  {
    "path": "presentation/css/theme/README.md",
    "chars": 1738,
    "preview": "## Dependencies\n\nThemes are written using Sass to keep things modular and reduce the need for repeated selectors across "
  },
  {
    "path": "presentation/css/theme/beige.css",
    "chars": 6843,
    "preview": "@import url(../../lib/font/league-gothic/league-gothic.css);\n@import url(https://fonts.googleapis.com/css?family=Lato:40"
  },
  {
    "path": "presentation/css/theme/black.css",
    "chars": 6244,
    "preview": "@import url(../../lib/font/source-sans-pro/source-sans-pro.css);\n/**\n * Black theme for reveal.js. This is the opposite "
  },
  {
    "path": "presentation/css/theme/blood.css",
    "chars": 7350,
    "preview": "@import url(https://fonts.googleapis.com/css?family=Ubuntu:300,700,300italic,700italic);\n/**\n * Blood theme for reveal.j"
  },
  {
    "path": "presentation/css/theme/league.css",
    "chars": 6860,
    "preview": "@import url(../../lib/font/league-gothic/league-gothic.css);\n@import url(../../contrib/google/css/lato.css);\n/**\n * Leag"
  },
  {
    "path": "presentation/css/theme/moon.css",
    "chars": 6117,
    "preview": "@import url(../../lib/font/league-gothic/league-gothic.css);\n@import url(https://fonts.googleapis.com/css?family=Lato:40"
  },
  {
    "path": "presentation/css/theme/night.css",
    "chars": 6032,
    "preview": "@import url(https://fonts.googleapis.com/css?family=Montserrat:700);\n@import url(https://fonts.googleapis.com/css?family"
  },
  {
    "path": "presentation/css/theme/serif.css",
    "chars": 6106,
    "preview": "/**\n * A simple theme for reveal.js presentations, similar\n * to the default theme. The accent color is brown.\n *\n * Thi"
  },
  {
    "path": "presentation/css/theme/simple.css",
    "chars": 6239,
    "preview": "@import url(https://fonts.googleapis.com/css?family=News+Cycle:400,700);\n@import url(https://fonts.googleapis.com/css?fa"
  },
  {
    "path": "presentation/css/theme/sky.css",
    "chars": 6640,
    "preview": "@import url(https://fonts.googleapis.com/css?family=Quicksand:400,700,400italic,700italic);\n@import url(https://fonts.go"
  },
  {
    "path": "presentation/css/theme/solarized.css",
    "chars": 6118,
    "preview": "@import url(../../lib/font/league-gothic/league-gothic.css);\n@import url(https://fonts.googleapis.com/css?family=Lato:40"
  },
  {
    "path": "presentation/css/theme/source/beige.scss",
    "chars": 1225,
    "preview": "/**\n * Beige theme for reveal.js.\n *\n * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se\n */\n\n\n// Default mixins"
  },
  {
    "path": "presentation/css/theme/source/black.scss",
    "chars": 1191,
    "preview": "/**\n * Black theme for reveal.js. This is the opposite of the 'white' theme.\n *\n * Copyright (C) 2015 Hakim El Hattab, h"
  },
  {
    "path": "presentation/css/theme/source/blood.scss",
    "chars": 2074,
    "preview": "/**\n * Blood theme for reveal.js\n * Author: Walther http://github.com/Walther\n *\n * Designed to be used with highlight.j"
  },
  {
    "path": "presentation/css/theme/source/league.scss",
    "chars": 1103,
    "preview": "/**\n * League theme for reveal.js.\n *\n * This was the default theme pre-3.0.0.\n *\n * Copyright (C) 2011-2012 Hakim El Ha"
  },
  {
    "path": "presentation/css/theme/source/moon.scss",
    "chars": 1269,
    "preview": "/**\n * Solarized Dark theme for reveal.js.\n * Author: Achim Staebler\n */\n\n\n// Default mixins and settings --------------"
  },
  {
    "path": "presentation/css/theme/source/night.scss",
    "chars": 966,
    "preview": "/**\n * Black theme for reveal.js.\n *\n * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se\n */\n\n\n// Default mixins"
  },
  {
    "path": "presentation/css/theme/source/serif.scss",
    "chars": 991,
    "preview": "/**\n * A simple theme for reveal.js presentations, similar\n * to the default theme. The accent color is brown.\n *\n * Thi"
  },
  {
    "path": "presentation/css/theme/source/simple.scss",
    "chars": 1161,
    "preview": "/**\n * A simple theme for reveal.js presentations, similar\n * to the default theme. The accent color is darkblue.\n *\n * "
  },
  {
    "path": "presentation/css/theme/source/sky.scss",
    "chars": 1145,
    "preview": "/**\n * Sky theme for reveal.js.\n *\n * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se\n */\n\n\n// Default mixins a"
  },
  {
    "path": "presentation/css/theme/source/solarized.scss",
    "chars": 1409,
    "preview": "/**\n * Solarized Light theme for reveal.js.\n * Author: Achim Staebler\n */\n\n\n// Default mixins and settings -------------"
  },
  {
    "path": "presentation/css/theme/source/white.scss",
    "chars": 1190,
    "preview": "/**\n * White theme for reveal.js. This is the opposite of the 'black' theme.\n *\n * Copyright (C) 2015 Hakim El Hattab, h"
  },
  {
    "path": "presentation/css/theme/template/mixins.scss",
    "chars": 1619,
    "preview": "@mixin vertical-gradient( $top, $bottom ) {\n\tbackground: $top;\n\tbackground: -moz-linear-gradient( top, $top 0%, $bottom "
  },
  {
    "path": "presentation/css/theme/template/settings.scss",
    "chars": 1034,
    "preview": "// Base settings for all themes that can optionally be\n// overridden by the super-theme\n\n// Background of the presentati"
  },
  {
    "path": "presentation/css/theme/template/theme.scss",
    "chars": 6016,
    "preview": "// Base theme template for reveal.js\n\n/*********************************************\n * GLOBAL STYLES\n *****************"
  },
  {
    "path": "presentation/css/theme/white.css",
    "chars": 6237,
    "preview": "@import url(../../lib/font/source-sans-pro/source-sans-pro.css);\n/**\n * White theme for reveal.js. This is the opposite "
  },
  {
    "path": "presentation/index.html",
    "chars": 7115,
    "preview": "<!doctype html>\n<html lang=\"en\">\n\n  <head>\n    <meta charset=\"utf-8\">\n\n    <title>Paperless</title>\n\n    <meta name=\"des"
  },
  {
    "path": "presentation/js/reveal.js",
    "chars": 117052,
    "preview": "/*!\n * reveal.js\n * http://lab.hakim.se/reveal-js\n * MIT licensed\n *\n * Copyright (C) 2015 Hakim El Hattab, http://hakim"
  },
  {
    "path": "presentation/lib/css/zenburn.css",
    "chars": 1856,
    "preview": "/*\n\nZenburn style from voldmar.ru (c) Vladimir Epifanov <voldmar@voldmar.ru>\nbased on dark.css by Ivan Sagalaev\n\n*/\n\n.hl"
  },
  {
    "path": "presentation/lib/font/league-gothic/LICENSE",
    "chars": 92,
    "preview": "SIL Open Font License (OFL)\nhttp://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL\n"
  },
  {
    "path": "presentation/lib/font/league-gothic/league-gothic.css",
    "chars": 308,
    "preview": "@font-face {\n    font-family: 'League Gothic';\n    src: url('league-gothic.eot');\n    src: url('league-gothic.eot?#iefix"
  },
  {
    "path": "presentation/lib/font/source-sans-pro/LICENSE",
    "chars": 4484,
    "preview": "SIL Open Font License\n\nCopyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name "
  },
  {
    "path": "presentation/lib/font/source-sans-pro/source-sans-pro.css",
    "chars": 1424,
    "preview": "@font-face {\n    font-family: 'Source Sans Pro';\n    src: url('source-sans-pro-regular.eot');\n    src: url('source-sans-"
  },
  {
    "path": "presentation/lib/js/classList.js",
    "chars": 1582,
    "preview": "/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js*/\nif(typeof document!==\"undefined\"&&!(\""
  },
  {
    "path": "presentation/lib/js/html5shiv.js",
    "chars": 235,
    "preview": "document.createElement('header');\ndocument.createElement('nav');\ndocument.createElement('section');\ndocument.createEleme"
  },
  {
    "path": "presentation/plugin/highlight/highlight.js",
    "chars": 241937,
    "preview": "// START CUSTOM REVEAL.JS INTEGRATION\n(function() {\n\tif( typeof window.addEventListener === 'function' ) {\n\t\tvar hljs_no"
  },
  {
    "path": "presentation/plugin/leap/leap.js",
    "chars": 84428,
    "preview": "/*\n * Copyright (c) 2013, Leap Motion, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary fo"
  },
  {
    "path": "presentation/plugin/markdown/example.html",
    "chars": 4173,
    "preview": "<!doctype html>\n<html lang=\"en\">\n\n\t<head>\n\t\t<meta charset=\"utf-8\">\n\n\t\t<title>reveal.js - Markdown Demo</title>\n\n\t\t<link "
  },
  {
    "path": "presentation/plugin/markdown/example.md",
    "chars": 230,
    "preview": "# Markdown Demo\n\n\n\n## External 1.1\n\nContent 1.1\n\nNote: This will only appear in the speaker notes window.\n\n\n## External "
  },
  {
    "path": "presentation/plugin/markdown/markdown.js",
    "chars": 11747,
    "preview": "/**\n * The reveal.js markdown plugin. Handles parsing of\n * markdown inside of presentations as well as loading\n * of ex"
  },
  {
    "path": "presentation/plugin/markdown/marked.js",
    "chars": 15810,
    "preview": "/**\n * marked - a markdown parser\n * Copyright (c) 2011-2013, Christopher Jeffrey. (MIT Licensed)\n * https://github.com/"
  },
  {
    "path": "presentation/plugin/math/math.js",
    "chars": 1617,
    "preview": "/**\n * A plugin which enables rendering of math equations inside\n * of reveal.js slides. Essentially a thin wrapper for "
  },
  {
    "path": "presentation/plugin/multiplex/client.js",
    "chars": 403,
    "preview": "(function() {\n\tvar multiplex = Reveal.getConfig().multiplex;\n\tvar socketId = multiplex.id;\n\tvar socket = io.connect(mult"
  },
  {
    "path": "presentation/plugin/multiplex/index.js",
    "chars": 1526,
    "preview": "var express\t\t= require('express');\nvar fs\t\t\t= require('fs');\nvar io\t\t\t= require('socket.io');\nvar crypto\t\t= require('cry"
  },
  {
    "path": "presentation/plugin/multiplex/master.js",
    "chars": 1402,
    "preview": "(function() {\n\t// Don't emit events from inside of notes windows\n\tif ( window.location.search.match( /receiver/gi ) ) { "
  },
  {
    "path": "presentation/plugin/notes/notes.html",
    "chars": 9856,
    "preview": "<!doctype html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"utf-8\">\n\n\t\t<title>reveal.js - Slide Notes</title>\n\n\t\t<style>\n\t"
  },
  {
    "path": "presentation/plugin/notes/notes.js",
    "chars": 3666,
    "preview": "/**\n * Handles opening of and synchronization with the reveal.js\n * notes window.\n *\n * Handshake process:\n * 1. This wi"
  },
  {
    "path": "presentation/plugin/notes-server/client.js",
    "chars": 1719,
    "preview": "(function() {\n\n\t// don't emit events from inside the previews themselves\n\tif( window.location.search.match( /receiver/gi"
  },
  {
    "path": "presentation/plugin/notes-server/index.js",
    "chars": 1691,
    "preview": "var express   = require('express');\nvar fs        = require('fs');\nvar io        = require('socket.io');\nvar _         ="
  },
  {
    "path": "presentation/plugin/notes-server/notes.html",
    "chars": 9029,
    "preview": "<!doctype html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"utf-8\">\n\n\t\t<title>reveal.js - Slide Notes</title>\n\n\t\t<style>\n\t"
  },
  {
    "path": "presentation/plugin/print-pdf/print-pdf.js",
    "chars": 1214,
    "preview": "/**\n * phantomjs script for printing presentations to PDF.\n *\n * Example:\n * phantomjs print-pdf.js \"http://lab.hakim.se"
  },
  {
    "path": "presentation/plugin/remotes/remotes.js",
    "chars": 1483,
    "preview": "/**\n * Touch-based remote controller for your presentation courtesy \n * of the folks at http://remotes.io\n */\n\n(function"
  },
  {
    "path": "presentation/plugin/search/search.js",
    "chars": 7151,
    "preview": "/*\n * Handles finding a text string anywhere in the slides and showing the next occurrence to the user\n * by navigatatin"
  },
  {
    "path": "presentation/plugin/zoom-js/zoom.js",
    "chars": 7981,
    "preview": "// Custom reveal.js integration\n(function(){\n\tvar isEnabled = true;\n\n\tdocument.querySelector( '.reveal' ).addEventListen"
  },
  {
    "path": "requirements.txt",
    "chars": 1519,
    "preview": "-i https://pypi.python.org/simple\nalabaster==0.7.12\napipkg==1.5\natomicwrites==1.3.0\nattrs==19.1.0\nbabel==2.7.0\nbrotli==1"
  },
  {
    "path": "resources/logo/print/eps/Black logo - no background.eps",
    "chars": 36316,
    "preview": "%!PS-Adobe-3.0 EPSF-3.0\n%Produced by poppler pdftops version: 0.59.0 (http://poppler.freedesktop.org)\n%%Creator: Chromiu"
  },
  {
    "path": "resources/logo/print/eps/Color logo - no background.eps",
    "chars": 36394,
    "preview": "%!PS-Adobe-3.0 EPSF-3.0\n%Produced by poppler pdftops version: 0.59.0 (http://poppler.freedesktop.org)\n%%Creator: Chromiu"
  },
  {
    "path": "resources/logo/print/eps/Color logo with background.eps",
    "chars": 36522,
    "preview": "%!PS-Adobe-3.0 EPSF-3.0\n%Produced by poppler pdftops version: 0.59.0 (http://poppler.freedesktop.org)\n%%Creator: Chromiu"
  },
  {
    "path": "resources/logo/print/eps/White logo - no background.eps",
    "chars": 36372,
    "preview": "%!PS-Adobe-3.0 EPSF-3.0\n%Produced by poppler pdftops version: 0.59.0 (http://poppler.freedesktop.org)\n%%Creator: Chromiu"
  },
  {
    "path": "scripts/docker-entrypoint.sh",
    "chars": 4039,
    "preview": "#!/bin/bash\nset -e\n\n# Source: https://github.com/sameersbn/docker-gitlab/\nmap_uidgid() {\n    USERMAP_ORIG_UID=$(id -u pa"
  },
  {
    "path": "scripts/gunicorn.conf",
    "chars": 1241,
    "preview": "bind = '127.0.0.1:8000'\nbacklog = 2048\nworkers = 3\nworker_class = 'sync'\nworker_connections = 1000\ntimeout = 20\nkeepaliv"
  },
  {
    "path": "scripts/paperless-consumer.service",
    "chars": 230,
    "preview": "[Unit]\nDescription=Paperless consumer\n\n[Service]\nUser=paperless\nGroup=paperless\nExecStart=/home/paperless/project/virtua"
  },
  {
    "path": "scripts/paperless-webserver.service",
    "chars": 280,
    "preview": "[Unit]\nDescription=Paperless webserver\nAfter=network.target\nWants=network.target\n\n[Service]\nUser=paperless\nGroup=paperle"
  },
  {
    "path": "scripts/post-consumption-example.sh",
    "chars": 678,
    "preview": "#!/usr/bin/env bash\n\nDOCUMENT_ID=${1}\nDOCUMENT_FILE_NAME=${2}\nDOCUMENT_SOURCE_PATH=${3}\nDOCUMENT_THUMBNAIL_PATH=${4}\nDOC"
  },
  {
    "path": "src/documents/__init__.py",
    "chars": 43,
    "preview": "from .checks import changed_password_check\n"
  },
  {
    "path": "src/documents/actions.py",
    "chars": 4965,
    "preview": "from django.contrib import messages\nfrom django.contrib.admin import helpers\nfrom django.contrib.admin.utils import mode"
  },
  {
    "path": "src/documents/admin.py",
    "chars": 11253,
    "preview": "from datetime import datetime, timedelta\n\nfrom django.conf import settings\nfrom django.contrib import admin, messages\nfr"
  },
  {
    "path": "src/documents/apps.py",
    "chars": 935,
    "preview": "from django.apps import AppConfig\nfrom django.db.models.signals import post_delete\n\n\nclass DocumentsConfig(AppConfig):\n\n"
  },
  {
    "path": "src/documents/checks.py",
    "chars": 1184,
    "preview": "import textwrap\n\nfrom django.conf import settings\nfrom django.core.checks import Error, register\nfrom django.db.utils im"
  },
  {
    "path": "src/documents/consumer.py",
    "chars": 8180,
    "preview": "from django.db import transaction\nimport datetime\nimport hashlib\nimport logging\nimport os\nimport re\nimport time\nimport u"
  },
  {
    "path": "src/documents/filters.py",
    "chars": 1374,
    "preview": "from django_filters.rest_framework import BooleanFilter, FilterSet\n\nfrom .models import Correspondent, Document, Tag\n\n\nC"
  },
  {
    "path": "src/documents/forms.py",
    "chars": 2874,
    "preview": "import magic\nimport os\n\nfrom datetime import datetime\nfrom time import mktime\n\nfrom django import forms\nfrom django.conf"
  },
  {
    "path": "src/documents/loggers.py",
    "chars": 646,
    "preview": "import logging\n\n\nclass PaperlessLogger(logging.StreamHandler):\n    \"\"\"\n    A logger smart enough to know to log some kin"
  },
  {
    "path": "src/documents/mail.py",
    "chars": 7237,
    "preview": "import datetime\nimport imaplib\nimport logging\nimport os\nimport re\nimport time\nimport uuid\n\nfrom base64 import b64decode\n"
  },
  {
    "path": "src/documents/management/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/documents/management/commands/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/documents/management/commands/change_storage_type.py",
    "chars": 4216,
    "preview": "import os\n\nfrom django.conf import settings\nfrom django.core.management.base import BaseCommand, CommandError\nfrom termc"
  },
  {
    "path": "src/documents/management/commands/document_consumer.py",
    "chars": 5090,
    "preview": "import logging\nimport os\nimport time\n\nfrom django.conf import settings\nfrom django.core.management.base import BaseComma"
  },
  {
    "path": "src/documents/management/commands/document_correspondents.py",
    "chars": 2701,
    "preview": "import sys\n\nfrom django.core.management.base import BaseCommand\n\nfrom documents.models import Correspondent, Document\n\nf"
  },
  {
    "path": "src/documents/management/commands/document_exporter.py",
    "chars": 4412,
    "preview": "import json\nimport os\nimport time\nimport shutil\n\nfrom django.core.management.base import BaseCommand, CommandError\nfrom "
  },
  {
    "path": "src/documents/management/commands/document_importer.py",
    "chars": 4156,
    "preview": "import json\nimport os\nimport shutil\n\nfrom django.conf import settings\nfrom django.core.management.base import BaseComman"
  },
  {
    "path": "src/documents/management/commands/document_logs.py",
    "chars": 283,
    "preview": "from django.core.management.base import BaseCommand\n\nfrom documents.models import Log\n\n\nclass Command(BaseCommand):\n\n   "
  },
  {
    "path": "src/documents/management/commands/document_renamer.py",
    "chars": 658,
    "preview": "from django.core.management.base import BaseCommand\n\nfrom documents.models import Document, Tag\n\nfrom ...mixins import R"
  },
  {
    "path": "src/documents/management/commands/document_retagger.py",
    "chars": 1005,
    "preview": "from django.core.management.base import BaseCommand\n\nfrom documents.models import Document, Tag\n\nfrom ...mixins import R"
  },
  {
    "path": "src/documents/management/commands/loaddata_stdin.py",
    "chars": 659,
    "preview": "import sys\n\nfrom django.core.management.commands.loaddata import Command as LoadDataCommand\n\n\nclass Command(LoadDataComm"
  },
  {
    "path": "src/documents/managers.py",
    "chars": 2051,
    "preview": "from django.conf import settings\n\nfrom django.db import models\nfrom django.db.models.aggregates import Max\n\n\nclass Group"
  },
  {
    "path": "src/documents/migrations/0001_initial.py",
    "chars": 951,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.9 on 2015-12-20 19:10\nfrom __future__ import unicode_literals\n\nfrom djan"
  },
  {
    "path": "src/documents/migrations/0002_auto_20151226_1316.py",
    "chars": 644,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.9 on 2015-12-26 13:16\nfrom __future__ import unicode_literals\n\nfrom djan"
  },
  {
    "path": "src/documents/migrations/0003_sender.py",
    "chars": 1942,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.9 on 2016-01-11 12:21\nfrom __future__ import unicode_literals\n\nfrom djan"
  },
  {
    "path": "src/documents/migrations/0004_auto_20160114_1844.py",
    "chars": 576,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.9 on 2016-01-14 18:44\nfrom __future__ import unicode_literals\n\nfrom djan"
  },
  {
    "path": "src/documents/migrations/0005_auto_20160123_0313.py",
    "chars": 410,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.9 on 2016-01-23 03:13\nfrom __future__ import unicode_literals\n\nfrom djan"
  },
  {
    "path": "src/documents/migrations/0006_auto_20160123_0430.py",
    "chars": 1359,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.9 on 2016-01-23 04:30\nfrom __future__ import unicode_literals\n\nfrom djan"
  },
  {
    "path": "src/documents/migrations/0007_auto_20160126_2114.py",
    "chars": 1579,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.9 on 2016-01-26 21:14\nfrom __future__ import unicode_literals\n\nfrom djan"
  },
  {
    "path": "src/documents/migrations/0008_document_file_type.py",
    "chars": 814,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.9 on 2016-01-29 22:58\nfrom __future__ import unicode_literals\n\nfrom djan"
  },
  {
    "path": "src/documents/migrations/0009_auto_20160214_0040.py",
    "chars": 1030,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.9 on 2016-02-14 00:40\nfrom __future__ import unicode_literals\n\nfrom djan"
  },
  {
    "path": "src/documents/migrations/0010_log.py",
    "chars": 1117,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.9 on 2016-02-27 17:54\nfrom __future__ import unicode_literals\n\nfrom djan"
  },
  {
    "path": "src/documents/migrations/0011_auto_20160303_1929.py",
    "chars": 693,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.9.2 on 2016-03-03 19:29\nfrom __future__ import unicode_literals\n\nfrom dj"
  },
  {
    "path": "src/documents/migrations/0012_auto_20160305_0040.py",
    "chars": 3626,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.9.2 on 2016-03-05 00:40\nfrom __future__ import unicode_literals\n\nimport "
  },
  {
    "path": "src/documents/migrations/0013_auto_20160325_2111.py",
    "chars": 1522,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.9.4 on 2016-03-25 21:11\nfrom __future__ import unicode_literals\n\nfrom dj"
  },
  {
    "path": "src/documents/migrations/0014_document_checksum.py",
    "chars": 5588,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.9.4 on 2016-03-28 19:09\nfrom __future__ import unicode_literals\n\nimport "
  },
  {
    "path": "src/documents/migrations/0015_add_insensitive_to_match.py",
    "chars": 941,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.10.2 on 2016-10-05 21:38\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/documents/migrations/0016_auto_20170325_1558.py",
    "chars": 658,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.10.5 on 2017-03-25 15:58\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/documents/migrations/0017_auto_20170512_0507.py",
    "chars": 2206,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.10.5 on 2017-05-12 05:07\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/documents/migrations/0018_auto_20170715_1712.py",
    "chars": 606,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.10.5 on 2017-07-15 17:12\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/documents/migrations/0019_add_consumer_user.py",
    "chars": 573,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.10.5 on 2017-07-15 17:12\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/documents/migrations/0020_document_added.py",
    "chars": 750,
    "preview": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\nimport django."
  },
  {
    "path": "src/documents/migrations/0021_document_storage_type.py",
    "chars": 998,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.10 on 2018-02-04 13:07\nfrom __future__ import unicode_literals\n\nfrom "
  },
  {
    "path": "src/documents/migrations/0022_auto_20181007_1420.py",
    "chars": 1629,
    "preview": "# Generated by Django 2.0.8 on 2018-10-07 14:20\n\nfrom django.db import migrations, models\nfrom django.utils.text import "
  },
  {
    "path": "src/documents/migrations/0023_document_current_filename.py",
    "chars": 1044,
    "preview": "# Generated by Django 2.0.10 on 2019-04-26 18:57\n\nfrom django.db import migrations, models\n\n\ndef set_filename(apps, sche"
  },
  {
    "path": "src/documents/migrations/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/documents/mixins.py",
    "chars": 231,
    "preview": "class Renderable:\n    \"\"\"\n    A handy mixin to make it easier/cleaner to print output based on a\n    verbosity value.\n  "
  },
  {
    "path": "src/documents/models.py",
    "chars": 23742,
    "preview": "# coding=utf-8\n\nimport logging\nimport os\nimport re\nimport uuid\nfrom collections import OrderedDict\n\nimport dateutil.pars"
  },
  {
    "path": "src/documents/parsers.py",
    "chars": 5551,
    "preview": "import logging\nimport os\nimport re\nimport shutil\nimport subprocess\nimport tempfile\n\nimport dateparser\nfrom django.conf i"
  },
  {
    "path": "src/documents/serialisers.py",
    "chars": 1773,
    "preview": "from rest_framework import serializers\n\nfrom .models import Correspondent, Tag, Document, Log\n\n\nclass CorrespondentSeria"
  },
  {
    "path": "src/documents/settings.py",
    "chars": 192,
    "preview": "# Defines the names of file/thumbnail for the manifest\n# for exporting/importing commands\nEXPORTER_FILE_NAME = \"__export"
  },
  {
    "path": "src/documents/signals/__init__.py",
    "chars": 229,
    "preview": "from django.dispatch import Signal\n\ndocument_consumption_started = Signal(providing_args=[\"filename\"])\ndocument_consumpt"
  },
  {
    "path": "src/documents/signals/handlers.py",
    "chars": 3130,
    "preview": "import logging\nimport os\nfrom subprocess import Popen\n\nfrom django.conf import settings\nfrom django.contrib.admin.models"
  },
  {
    "path": "src/documents/static/js/colours.js",
    "chars": 2263,
    "preview": "// The following jQuery snippet will add a small square next to the selection\n// drop-down on the `Add tag` page that wi"
  },
  {
    "path": "src/documents/static/paperless.css",
    "chars": 343,
    "preview": "th.column-document,\ntd.field-document {\n  text-align: center;\n}\n\ntd a.tag {\n  padding: 0 0.5em;\n  color: #ffffff;\n  bord"
  },
  {
    "path": "src/documents/templates/admin/base_site.html",
    "chars": 2026,
    "preview": "{% extends 'admin/base_site.html' %}\n\n{# NOTE: This should probably be extending base.html.  See CSS comment below detai"
  },
  {
    "path": "src/documents/templates/admin/documents/document/change_form.html",
    "chars": 1267,
    "preview": "{% extends 'admin/change_form.html' %}\n\n{% block content %}\n\n{{ block.super }}\n<div class=\"side-preview\">\n  <h2>Preview<"
  },
  {
    "path": "src/documents/templates/admin/documents/document/change_list.html",
    "chars": 375,
    "preview": "{% extends 'admin/change_list.html' %}\n\n\n{% load admin_actions from admin_list%}\n{% load result_list from hacks %}\n\n\n{% "
  },
  {
    "path": "src/documents/templates/admin/documents/document/change_list_results.html",
    "chars": 4621,
    "preview": "{% load i18n %}\n\n<style>\n  .grid *, .grid *:after, .grid *:before {\n    -webkit-box-sizing: border-box;\n    -moz-box-siz"
  },
  {
    "path": "src/documents/templates/admin/documents/document/select_object.html",
    "chars": 1482,
    "preview": "{% extends \"admin/base_site.html\" %}\n\n\n{% load i18n l10n admin_urls static %}\n{% load staticfiles %}\n\n\n{% block extrahea"
  }
]

// ... and 58 more files (download for full content)

About this extraction

This page contains the full source code of the the-paperless-project/paperless GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 258 files (2.0 MB), approximately 550.1k tokens, and a symbol index with 638 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!