mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-11-03 03:16:10 -06:00 
			
		
		
		
	Merge branch 'dev' into celery-tasks
This commit is contained in:
		
							
								
								
									
										36
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								.travis.yml
									
									
									
									
									
								
							@@ -1,13 +1,39 @@
 | 
			
		||||
language: python
 | 
			
		||||
 | 
			
		||||
python:
 | 
			
		||||
  - "3.6"
 | 
			
		||||
  - "3.7"
 | 
			
		||||
  - "3.8"
 | 
			
		||||
jobs:
 | 
			
		||||
  include:
 | 
			
		||||
    - name: "Paperless on Python 3.6"
 | 
			
		||||
      python: "3.6"
 | 
			
		||||
 | 
			
		||||
    - name: "Paperless on Python 3.7"
 | 
			
		||||
      python: "3.7"
 | 
			
		||||
 | 
			
		||||
    - name: "Paperless on Python 3.8"
 | 
			
		||||
      python: "3.8"
 | 
			
		||||
 | 
			
		||||
    - name: "Documentation"
 | 
			
		||||
      script:
 | 
			
		||||
        - cd docs/
 | 
			
		||||
        - make html
 | 
			
		||||
      after_success: true
 | 
			
		||||
 | 
			
		||||
    - name: "Front end"
 | 
			
		||||
      language: node_js
 | 
			
		||||
      node_js:
 | 
			
		||||
        - 15
 | 
			
		||||
      before_install: true
 | 
			
		||||
      install:
 | 
			
		||||
        - cd src-ui/
 | 
			
		||||
        - npm install -g @angular/cli
 | 
			
		||||
        - npm install
 | 
			
		||||
      script:
 | 
			
		||||
        - ng build --prod
 | 
			
		||||
      after_success: true
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
before_install:
 | 
			
		||||
  - sudo apt-get update -qq
 | 
			
		||||
  - sudo apt-get install -qq libpoppler-cpp-dev unpaper tesseract-ocr
 | 
			
		||||
  - sudo apt-get install -qq libpoppler-cpp-dev unpaper tesseract-ocr imagemagick ghostscript
 | 
			
		||||
 | 
			
		||||
install:
 | 
			
		||||
  - pip install --upgrade pipenv
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										48
									
								
								Pipfile
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								Pipfile
									
									
									
									
									
								
							@@ -9,32 +9,32 @@ verify_ssl = true
 | 
			
		||||
name = "piwheels"
 | 
			
		||||
 | 
			
		||||
[packages]
 | 
			
		||||
django = "~=3.1"
 | 
			
		||||
pillow = "*"
 | 
			
		||||
dateparser = "~=0.7"
 | 
			
		||||
dateparser = "~=0.7.6"
 | 
			
		||||
django = "~=3.1.3"
 | 
			
		||||
django-cors-headers = "*"
 | 
			
		||||
djangorestframework = "~=3.12"
 | 
			
		||||
python-gnupg = "*"
 | 
			
		||||
python-dotenv = "*"
 | 
			
		||||
filemagic = "*"
 | 
			
		||||
pyocr = "~=0.7"
 | 
			
		||||
django-extensions = "*"
 | 
			
		||||
django-filter = "~=2.4.0"
 | 
			
		||||
django-q = "~=1.3.4"
 | 
			
		||||
djangorestframework = "~=3.12.2"
 | 
			
		||||
fuzzywuzzy = "*"
 | 
			
		||||
gunicorn = "*"
 | 
			
		||||
imap-tools = "*"
 | 
			
		||||
langdetect = "*"
 | 
			
		||||
pdftotext = "*"
 | 
			
		||||
django-filter = "~=2.4"
 | 
			
		||||
python-dateutil = "*"
 | 
			
		||||
psycopg2-binary = "*"
 | 
			
		||||
scikit-learn="~=0.23"
 | 
			
		||||
whoosh="~=2.7"
 | 
			
		||||
gunicorn = "*"
 | 
			
		||||
whitenoise = "~=5.2"
 | 
			
		||||
fuzzywuzzy = "*"
 | 
			
		||||
python-Levenshtein = "*"
 | 
			
		||||
django-extensions = "*"
 | 
			
		||||
watchdog = "*"
 | 
			
		||||
pathvalidate = "*"
 | 
			
		||||
django-q = "*"
 | 
			
		||||
pillow = "*"
 | 
			
		||||
pyocr = "~=0.7.2"
 | 
			
		||||
python-gnupg = "*"
 | 
			
		||||
python-dotenv = "*"
 | 
			
		||||
python-dateutil = "*"
 | 
			
		||||
python-Levenshtein = "*"
 | 
			
		||||
python-magic = "*"
 | 
			
		||||
psycopg2-binary = "*"
 | 
			
		||||
redis = "*"
 | 
			
		||||
imap-tools = "*"
 | 
			
		||||
scikit-learn="~=0.23.2"
 | 
			
		||||
whitenoise = "~=5.2.0"
 | 
			
		||||
watchdog = "*"
 | 
			
		||||
whoosh="~=2.7.4"
 | 
			
		||||
channels = "~=3.0"
 | 
			
		||||
channels-redis = "*"
 | 
			
		||||
daphne = "~=3.0"
 | 
			
		||||
@@ -42,13 +42,13 @@ daphne = "~=3.0"
 | 
			
		||||
[dev-packages]
 | 
			
		||||
coveralls = "*"
 | 
			
		||||
factory-boy = "*"
 | 
			
		||||
sphinx = "~=3.3"
 | 
			
		||||
tox = "*"
 | 
			
		||||
pycodestyle = "*"
 | 
			
		||||
pytest = "*"
 | 
			
		||||
pytest-cov = "*"
 | 
			
		||||
pytest-django = "*"
 | 
			
		||||
pytest-sugar = "*"
 | 
			
		||||
pytest-env = "*"
 | 
			
		||||
pytest-sugar = "*"
 | 
			
		||||
pytest-xdist = "*"
 | 
			
		||||
sphinx = "~=3.3"
 | 
			
		||||
sphinx_rtd_theme = "*"
 | 
			
		||||
tox = "*"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										556
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										556
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
								
							@@ -1,7 +1,7 @@
 | 
			
		||||
{
 | 
			
		||||
    "_meta": {
 | 
			
		||||
        "hash": {
 | 
			
		||||
            "sha256": "ef3638ed4905e0809823dc1cfefd8e5ee415cd9d33ec3f23e483fb60b87d6fe6"
 | 
			
		||||
            "sha256": "ae2643b9cf0cf5741ae149fb6bc0c480de41329ce48e773eb4b5d760bc5e2244"
 | 
			
		||||
        },
 | 
			
		||||
        "pipfile-spec": 6,
 | 
			
		||||
        "requires": {},
 | 
			
		||||
@@ -19,13 +19,6 @@
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    "default": {
 | 
			
		||||
        "aioredis": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:15f8af30b044c771aee6787e5ec24694c048184c7b9e54c3b60c750a4b93273a",
 | 
			
		||||
                "sha256:b61808d7e97b7cd5a92ed574937a079c9387fdadd22bfbfa7ad2fd319ecc26e3"
 | 
			
		||||
            ],
 | 
			
		||||
            "version": "==1.3.1"
 | 
			
		||||
        },
 | 
			
		||||
        "arrow": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:e098abbd9af3665aea81bdd6c869e93af4feb078e98468dd351c383af187aac5",
 | 
			
		||||
@@ -42,39 +35,6 @@
 | 
			
		||||
            "markers": "python_version >= '3.5'",
 | 
			
		||||
            "version": "==3.3.1"
 | 
			
		||||
        },
 | 
			
		||||
        "async-timeout": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f",
 | 
			
		||||
                "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"
 | 
			
		||||
            ],
 | 
			
		||||
            "markers": "python_full_version >= '3.5.3'",
 | 
			
		||||
            "version": "==3.0.1"
 | 
			
		||||
        },
 | 
			
		||||
        "attrs": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6",
 | 
			
		||||
                "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"
 | 
			
		||||
            ],
 | 
			
		||||
            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
 | 
			
		||||
            "version": "==20.3.0"
 | 
			
		||||
        },
 | 
			
		||||
        "autobahn": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:1eafbbe363a7924fd21bb0b94ece9f3ac2a9aa9c2046e8a85e044f94e8ba2028",
 | 
			
		||||
                "sha256:24ce276d313e84d68241c3aef30d484f352b90a40168981b3640312c821df77b",
 | 
			
		||||
                "sha256:86bbce30cdd407137c57670993a8f9bfdfe3f8e994b889181d85e844d5aa8dfb"
 | 
			
		||||
            ],
 | 
			
		||||
            "markers": "python_version >= '3.5'",
 | 
			
		||||
            "version": "==20.7.1"
 | 
			
		||||
        },
 | 
			
		||||
        "automat": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:7979803c74610e11ef0c0d68a2942b152df52da55336e0c9d58daf1831cbdf33",
 | 
			
		||||
                "sha256:b6feb6455337df834f6c9962d6ccf771515b7d939bca142b29c20c2376bc6111",
 | 
			
		||||
                "sha256:d6d976cf8da698fc85fa7def46e2544493f78cb7ee72d2f4acd1a5c759a3060e"
 | 
			
		||||
            ],
 | 
			
		||||
            "version": "==20.2.0"
 | 
			
		||||
        },
 | 
			
		||||
        "blessed": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:7d4914079a6e8e14fbe080dcaf14dee596a088057cdc598561080e3266123b48",
 | 
			
		||||
@@ -82,110 +42,6 @@
 | 
			
		||||
            ],
 | 
			
		||||
            "version": "==1.17.11"
 | 
			
		||||
        },
 | 
			
		||||
        "cffi": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:005f2bfe11b6745d726dbb07ace4d53f057de66e336ff92d61b8c7e9c8f4777d",
 | 
			
		||||
                "sha256:09e96138280241bd355cd585148dec04dbbedb4f46128f340d696eaafc82dd7b",
 | 
			
		||||
                "sha256:0b1ad452cc824665ddc682400b62c9e4f5b64736a2ba99110712fdee5f2505c4",
 | 
			
		||||
                "sha256:0ef488305fdce2580c8b2708f22d7785ae222d9825d3094ab073e22e93dfe51f",
 | 
			
		||||
                "sha256:15f351bed09897fbda218e4db5a3d5c06328862f6198d4fb385f3e14e19decb3",
 | 
			
		||||
                "sha256:178a2db1589cb9b0b5b28a74ee0c9d4438bd96f8c6c0ac85662ff3c98f7f8d20",
 | 
			
		||||
                "sha256:22399ff4870fb4c7ef19fff6eeb20a8bbf15571913c181c78cb361024d574579",
 | 
			
		||||
                "sha256:23e5d2040367322824605bc29ae8ee9175200b92cb5483ac7d466927a9b3d537",
 | 
			
		||||
                "sha256:2791f68edc5749024b4722500e86303a10d342527e1e3bcac47f35fbd25b764e",
 | 
			
		||||
                "sha256:2f9674623ca39c9ebe38afa3da402e9326c245f0f5ceff0623dccdac15023e05",
 | 
			
		||||
                "sha256:3363e77a6176afb8823b6e06db78c46dbc4c7813b00a41300a4873b6ba63b171",
 | 
			
		||||
                "sha256:33c6cdc071ba5cd6d96769c8969a0531be2d08c2628a0143a10a7dcffa9719ca",
 | 
			
		||||
                "sha256:3b8eaf915ddc0709779889c472e553f0d3e8b7bdf62dab764c8921b09bf94522",
 | 
			
		||||
                "sha256:3cb3e1b9ec43256c4e0f8d2837267a70b0e1ca8c4f456685508ae6106b1f504c",
 | 
			
		||||
                "sha256:3eeeb0405fd145e714f7633a5173318bd88d8bbfc3dd0a5751f8c4f70ae629bc",
 | 
			
		||||
                "sha256:44f60519595eaca110f248e5017363d751b12782a6f2bd6a7041cba275215f5d",
 | 
			
		||||
                "sha256:4d7c26bfc1ea9f92084a1d75e11999e97b62d63128bcc90c3624d07813c52808",
 | 
			
		||||
                "sha256:529c4ed2e10437c205f38f3691a68be66c39197d01062618c55f74294a4a4828",
 | 
			
		||||
                "sha256:6642f15ad963b5092d65aed022d033c77763515fdc07095208f15d3563003869",
 | 
			
		||||
                "sha256:85ba797e1de5b48aa5a8427b6ba62cf69607c18c5d4eb747604b7302f1ec382d",
 | 
			
		||||
                "sha256:8f0f1e499e4000c4c347a124fa6a27d37608ced4fe9f7d45070563b7c4c370c9",
 | 
			
		||||
                "sha256:a624fae282e81ad2e4871bdb767e2c914d0539708c0f078b5b355258293c98b0",
 | 
			
		||||
                "sha256:b0358e6fefc74a16f745afa366acc89f979040e0cbc4eec55ab26ad1f6a9bfbc",
 | 
			
		||||
                "sha256:bbd2f4dfee1079f76943767fce837ade3087b578aeb9f69aec7857d5bf25db15",
 | 
			
		||||
                "sha256:bf39a9e19ce7298f1bd6a9758fa99707e9e5b1ebe5e90f2c3913a47bc548747c",
 | 
			
		||||
                "sha256:c11579638288e53fc94ad60022ff1b67865363e730ee41ad5e6f0a17188b327a",
 | 
			
		||||
                "sha256:c150eaa3dadbb2b5339675b88d4573c1be3cb6f2c33a6c83387e10cc0bf05bd3",
 | 
			
		||||
                "sha256:c53af463f4a40de78c58b8b2710ade243c81cbca641e34debf3396a9640d6ec1",
 | 
			
		||||
                "sha256:cb763ceceae04803adcc4e2d80d611ef201c73da32d8f2722e9d0ab0c7f10768",
 | 
			
		||||
                "sha256:cc75f58cdaf043fe6a7a6c04b3b5a0e694c6a9e24050967747251fb80d7bce0d",
 | 
			
		||||
                "sha256:d80998ed59176e8cba74028762fbd9b9153b9afc71ea118e63bbf5d4d0f9552b",
 | 
			
		||||
                "sha256:de31b5164d44ef4943db155b3e8e17929707cac1e5bd2f363e67a56e3af4af6e",
 | 
			
		||||
                "sha256:df90c0c9e383e8c3bdced39f113ecc36fa9c623dd04dd1b5199e9edc53389a95",
 | 
			
		||||
                "sha256:e66399cf0fc07de4dce4f588fc25bfe84a6d1285cc544e67987d22663393926d",
 | 
			
		||||
                "sha256:f0620511387790860b249b9241c2f13c3a80e21a73e0b861a2df24e9d6f56730",
 | 
			
		||||
                "sha256:f4eae045e6ab2bb54ca279733fe4eb85f1effda392666308250714e01907f394",
 | 
			
		||||
                "sha256:f92cdecb618e5fa4658aeb97d5eb3d2f47aa94ac6477c6daf0f306c5a3b9e6b1",
 | 
			
		||||
                "sha256:f92f789e4f9241cd262ad7a555ca2c648a98178a953af117ef7fad46aa1d5591"
 | 
			
		||||
            ],
 | 
			
		||||
            "version": "==1.14.3"
 | 
			
		||||
        },
 | 
			
		||||
        "channels": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:74db79c9eca616be69d38013b22083ab5d3f9ccda1ab5e69096b1bb7da2d9b18",
 | 
			
		||||
                "sha256:f50a6e79757a64c1e45e95e144a2ac5f1e99ee44a0718ab182c501f5e5abd268"
 | 
			
		||||
            ],
 | 
			
		||||
            "index": "pypi",
 | 
			
		||||
            "version": "==3.0.2"
 | 
			
		||||
        },
 | 
			
		||||
        "channels-redis": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:18d63f6462a58011740dc8eeb57ea4b31ec220eb551cb71b27de9c6779a549de",
 | 
			
		||||
                "sha256:2fb31a63b05373f6402da2e6a91a22b9e66eb8b56626c6bfc93e156c734c5ae6"
 | 
			
		||||
            ],
 | 
			
		||||
            "index": "pypi",
 | 
			
		||||
            "version": "==3.2.0"
 | 
			
		||||
        },
 | 
			
		||||
        "constantly": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35",
 | 
			
		||||
                "sha256:dd2fa9d6b1a51a83f0d7dd76293d734046aa176e384bf6e33b7e44880eb37c5d"
 | 
			
		||||
            ],
 | 
			
		||||
            "version": "==15.1.0"
 | 
			
		||||
        },
 | 
			
		||||
        "cryptography": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:07ca431b788249af92764e3be9a488aa1d39a0bc3be313d826bbec690417e538",
 | 
			
		||||
                "sha256:13b88a0bd044b4eae1ef40e265d006e34dbcde0c2f1e15eb9896501b2d8f6c6f",
 | 
			
		||||
                "sha256:257dab4f368fae15f378ea9a4d2799bf3696668062de0e9fa0ebb7a738a6917d",
 | 
			
		||||
                "sha256:32434673d8505b42c0de4de86da8c1620651abd24afe91ae0335597683ed1b77",
 | 
			
		||||
                "sha256:3cd75a683b15576cfc822c7c5742b3276e50b21a06672dc3a800a2d5da4ecd1b",
 | 
			
		||||
                "sha256:4e7268a0ca14536fecfdf2b00297d4e407da904718658c1ff1961c713f90fd33",
 | 
			
		||||
                "sha256:545a8550782dda68f8cdc75a6e3bf252017aa8f75f19f5a9ca940772fc0cb56e",
 | 
			
		||||
                "sha256:55d0b896631412b6f0c7de56e12eb3e261ac347fbaa5d5e705291a9016e5f8cb",
 | 
			
		||||
                "sha256:5849d59358547bf789ee7e0d7a9036b2d29e9a4ddf1ce5e06bb45634f995c53e",
 | 
			
		||||
                "sha256:59f7d4cfea9ef12eb9b14b83d79b432162a0a24a91ddc15c2c9bf76a68d96f2b",
 | 
			
		||||
                "sha256:6dc59630ecce8c1f558277ceb212c751d6730bd12c80ea96b4ac65637c4f55e7",
 | 
			
		||||
                "sha256:7117319b44ed1842c617d0a452383a5a052ec6aa726dfbaffa8b94c910444297",
 | 
			
		||||
                "sha256:75e8e6684cf0034f6bf2a97095cb95f81537b12b36a8fedf06e73050bb171c2d",
 | 
			
		||||
                "sha256:7b8d9d8d3a9bd240f453342981f765346c87ade811519f98664519696f8e6ab7",
 | 
			
		||||
                "sha256:a035a10686532b0587d58a606004aa20ad895c60c4d029afa245802347fab57b",
 | 
			
		||||
                "sha256:a4e27ed0b2504195f855b52052eadcc9795c59909c9d84314c5408687f933fc7",
 | 
			
		||||
                "sha256:a733671100cd26d816eed39507e585c156e4498293a907029969234e5e634bc4",
 | 
			
		||||
                "sha256:a75f306a16d9f9afebfbedc41c8c2351d8e61e818ba6b4c40815e2b5740bb6b8",
 | 
			
		||||
                "sha256:bd717aa029217b8ef94a7d21632a3bb5a4e7218a4513d2521c2a2fd63011e98b",
 | 
			
		||||
                "sha256:d25cecbac20713a7c3bc544372d42d8eafa89799f492a43b79e1dfd650484851",
 | 
			
		||||
                "sha256:d26a2557d8f9122f9bf445fc7034242f4375bd4e95ecda007667540270965b13",
 | 
			
		||||
                "sha256:d3545829ab42a66b84a9aaabf216a4dce7f16dbc76eb69be5c302ed6b8f4a29b",
 | 
			
		||||
                "sha256:d3d5e10be0cf2a12214ddee45c6bd203dab435e3d83b4560c03066eda600bfe3",
 | 
			
		||||
                "sha256:efe15aca4f64f3a7ea0c09c87826490e50ed166ce67368a68f315ea0807a20df"
 | 
			
		||||
            ],
 | 
			
		||||
            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
 | 
			
		||||
            "version": "==3.2.1"
 | 
			
		||||
        },
 | 
			
		||||
        "daphne": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:60856f7efa0b1e1b969efa074e8698bd09de4713ecc06e6a4d19d04c66c4a3bd",
 | 
			
		||||
                "sha256:b43e70d74ff832a634ff6c92badd208824e4530e08b340116517e5aad0aca774"
 | 
			
		||||
            ],
 | 
			
		||||
            "index": "pypi",
 | 
			
		||||
            "version": "==3.0.0"
 | 
			
		||||
        },
 | 
			
		||||
        "dateparser": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:7552c994f893b5cb8fcf103b4cd2ff7f57aab9bfd2619fdf0cf571c0740fd90b",
 | 
			
		||||
@@ -249,13 +105,6 @@
 | 
			
		||||
            "index": "pypi",
 | 
			
		||||
            "version": "==3.12.2"
 | 
			
		||||
        },
 | 
			
		||||
        "filemagic": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:e684359ef40820fe406f0ebc5bf8a78f89717bdb7fed688af68082d991d6dbf3"
 | 
			
		||||
            ],
 | 
			
		||||
            "index": "pypi",
 | 
			
		||||
            "version": "==1.6"
 | 
			
		||||
        },
 | 
			
		||||
        "fuzzywuzzy": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:45016e92264780e58972dca1b3d939ac864b78437422beecebb3095f8efd00e8",
 | 
			
		||||
@@ -272,91 +121,13 @@
 | 
			
		||||
            "index": "pypi",
 | 
			
		||||
            "version": "==20.0.4"
 | 
			
		||||
        },
 | 
			
		||||
        "hiredis": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:06a039208f83744a702279b894c8cf24c14fd63c59cd917dcde168b79eef0680",
 | 
			
		||||
                "sha256:0a909bf501459062aa1552be1461456518f367379fdc9fdb1f2ca5e4a1fdd7c0",
 | 
			
		||||
                "sha256:18402d9e54fb278cb9a8c638df6f1550aca36a009d47ecf5aa263a38600f35b0",
 | 
			
		||||
                "sha256:1e4cbbc3858ec7e680006e5ca590d89a5e083235988f26a004acf7244389ac01",
 | 
			
		||||
                "sha256:23344e3c2177baf6975fbfa361ed92eb7d36d08f454636e5054b3faa7c2aff8a",
 | 
			
		||||
                "sha256:289b31885b4996ce04cadfd5fc03d034dce8e2a8234479f7c9e23b9e245db06b",
 | 
			
		||||
                "sha256:2c1c570ae7bf1bab304f29427e2475fe1856814312c4a1cf1cd0ee133f07a3c6",
 | 
			
		||||
                "sha256:2c227c0ed371771ffda256034427320870e8ea2e4fd0c0a618c766e7c49aad73",
 | 
			
		||||
                "sha256:3bb9b63d319402cead8bbd9dd55dca3b667d2997e9a0d8a1f9b6cc274db4baee",
 | 
			
		||||
                "sha256:3ef2183de67b59930d2db8b8e8d4d58e00a50fcc5e92f4f678f6eed7a1c72d55",
 | 
			
		||||
                "sha256:43b8ed3dbfd9171e44c554cb4acf4ee4505caa84c5e341858b50ea27dd2b6e12",
 | 
			
		||||
                "sha256:47bcf3c5e6c1e87ceb86cdda2ee983fa0fe56a999e6185099b3c93a223f2fa9b",
 | 
			
		||||
                "sha256:5263db1e2e1e8ae30500cdd75a979ff99dcc184201e6b4b820d0de74834d2323",
 | 
			
		||||
                "sha256:5b1451727f02e7acbdf6aae4e06d75f66ee82966ff9114550381c3271a90f56c",
 | 
			
		||||
                "sha256:6996883a8a6ff9117cbb3d6f5b0dcbbae6fb9e31e1a3e4e2f95e0214d9a1c655",
 | 
			
		||||
                "sha256:6c96f64a54f030366657a54bb90b3093afc9c16c8e0dfa29fc0d6dbe169103a5",
 | 
			
		||||
                "sha256:7332d5c3e35154cd234fd79573736ddcf7a0ade7a986db35b6196b9171493e75",
 | 
			
		||||
                "sha256:7885b6f32c4a898e825bb7f56f36a02781ac4a951c63e4169f0afcf9c8c30dfb",
 | 
			
		||||
                "sha256:7b0f63f10a166583ab744a58baad04e0f52cfea1ac27bfa1b0c21a48d1003c23",
 | 
			
		||||
                "sha256:819f95d4eba3f9e484dd115ab7ab72845cf766b84286a00d4ecf76d33f1edca1",
 | 
			
		||||
                "sha256:8968eeaa4d37a38f8ca1f9dbe53526b69628edc9c42229a5b2f56d98bb828c1f",
 | 
			
		||||
                "sha256:89ebf69cb19a33d625db72d2ac589d26e936b8f7628531269accf4a3196e7872",
 | 
			
		||||
                "sha256:8daecd778c1da45b8bd54fd41ffcd471a86beed3d8e57a43acf7a8d63bba4058",
 | 
			
		||||
                "sha256:955ba8ea73cf3ed8bd2f963b4cb9f8f0dcb27becd2f4b3dd536fd24c45533454",
 | 
			
		||||
                "sha256:964f18a59f5a64c0170f684c417f4fe3e695a536612e13074c4dd5d1c6d7c882",
 | 
			
		||||
                "sha256:969843fbdfbf56cdb71da6f0bdf50f9985b8b8aeb630102945306cf10a9c6af2",
 | 
			
		||||
                "sha256:996021ef33e0f50b97ff2d6b5f422a0fe5577de21a8873b58a779a5ddd1c3132",
 | 
			
		||||
                "sha256:9e9c9078a7ce07e6fce366bd818be89365a35d2e4b163268f0ca9ba7e13bb2f6",
 | 
			
		||||
                "sha256:9f4e67f87e072de981570eaf7cb41444bbac7e92b05c8651dbab6eb1fb8d5a14",
 | 
			
		||||
                "sha256:a04901757cb0fb0f5602ac11dda48f5510f94372144d06c2563ba56c480b467c",
 | 
			
		||||
                "sha256:a7bf1492429f18d205f3a818da3ff1f242f60aa59006e53dee00b4ef592a3363",
 | 
			
		||||
                "sha256:aa0af2deb166a5e26e0d554b824605e660039b161e37ed4f01b8d04beec184f3",
 | 
			
		||||
                "sha256:abfb15a6a7822f0fae681785cb38860e7a2cb1616a708d53df557b3d76c5bfd4",
 | 
			
		||||
                "sha256:b253fe4df2afea4dfa6b1fa8c5fef212aff8bcaaeb4207e81eed05cb5e4a7919",
 | 
			
		||||
                "sha256:b27f082f47d23cffc4cf1388b84fdc45c4ef6015f906cd7e0d988d9e35d36349",
 | 
			
		||||
                "sha256:b33aea449e7f46738811fbc6f0b3177c6777a572207412bbbf6f525ffed001ae",
 | 
			
		||||
                "sha256:b39989b49e8aca9d224324d2650029eda410a4faf43f6afb0eb4f9acb7be6097",
 | 
			
		||||
                "sha256:b44f9421c4505c548435244d74037618f452844c5d3c67719d8a55e2613549da",
 | 
			
		||||
                "sha256:bcc371151d1512201d0214c36c0c150b1dc64f19c2b1a8c9cb1d7c7c15ebd93f",
 | 
			
		||||
                "sha256:c2851deeabd96d3f6283e9c6b26e0bfed4de2dc6fb15edf913e78b79fc5909ed",
 | 
			
		||||
                "sha256:cdfd501c7ac5b198c15df800a3a34c38345f5182e5f80770caf362bccca65628",
 | 
			
		||||
                "sha256:d2c0caffa47606d6d7c8af94ba42547bd2a441f06c74fd90a1ffe328524a6c64",
 | 
			
		||||
                "sha256:dcb2db95e629962db5a355047fb8aefb012df6c8ae608930d391619dbd96fd86",
 | 
			
		||||
                "sha256:e0eeb9c112fec2031927a1745788a181d0eecbacbed941fc5c4f7bc3f7b273bf",
 | 
			
		||||
                "sha256:e154891263306200260d7f3051982774d7b9ef35af3509d5adbbe539afd2610c",
 | 
			
		||||
                "sha256:e2e023a42dcbab8ed31f97c2bcdb980b7fbe0ada34037d87ba9d799664b58ded",
 | 
			
		||||
                "sha256:e64be68255234bb489a574c4f2f8df7029c98c81ec4d160d6cd836e7f0679390",
 | 
			
		||||
                "sha256:e82d6b930e02e80e5109b678c663a9ed210680ded81c1abaf54635d88d1da298"
 | 
			
		||||
            ],
 | 
			
		||||
            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
 | 
			
		||||
            "version": "==1.1.0"
 | 
			
		||||
        },
 | 
			
		||||
        "hyperlink": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:402c1b5fa066ea368f3118fc5a6f8505440b4d1a4ef12a844ca39332a4a29944",
 | 
			
		||||
                "sha256:47fcc7cd339c6cb2444463ec3277bdcfe142c8b1daf2160bdd52248deec815af",
 | 
			
		||||
                "sha256:c528d405766f15a2c536230de7e160b65a08e20264d8891b3eb03307b0df3c63"
 | 
			
		||||
            ],
 | 
			
		||||
            "version": "==20.0.1"
 | 
			
		||||
        },
 | 
			
		||||
        "idna": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:4a57a6379512ade94fa99e2fa46d3cd0f2f553040548d0e2958c6ed90ee48226",
 | 
			
		||||
                "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6",
 | 
			
		||||
                "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"
 | 
			
		||||
            ],
 | 
			
		||||
            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
 | 
			
		||||
            "version": "==2.10"
 | 
			
		||||
        },
 | 
			
		||||
        "imap-tools": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:070929b8ec429c0aad94588a37a2962eed656a119ab61dcf91489f20fe983f5d",
 | 
			
		||||
                "sha256:6232cd43748741496446871e889eb137351fc7a7e7f4c7888cd8c0fa28e20cda"
 | 
			
		||||
                "sha256:96e9a4ff6483462635737730a1df28e739faa71967b12a84f4363fb386542246",
 | 
			
		||||
                "sha256:a3ee1827dc4ff185b259b33d0238b091a87d489f63ee59959fcc81716456c602"
 | 
			
		||||
            ],
 | 
			
		||||
            "index": "pypi",
 | 
			
		||||
            "version": "==0.31.0"
 | 
			
		||||
        },
 | 
			
		||||
        "incremental": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:717e12246dddf231a349175f48d74d93e2897244939173b01974ab6661406b9f",
 | 
			
		||||
                "sha256:7b751696aaf36eebfab537e458929e194460051ccad279c72b755a167eebd4b3"
 | 
			
		||||
            ],
 | 
			
		||||
            "version": "==17.5.0"
 | 
			
		||||
            "version": "==0.32.0"
 | 
			
		||||
        },
 | 
			
		||||
        "joblib": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
@@ -369,37 +140,12 @@
 | 
			
		||||
        "langdetect": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:363795ea005f1243c958e953245dac5d814fabdc025c9afa91588c5fa6b2fa83",
 | 
			
		||||
                "sha256:ae53a024643df713274c297c0795dbfb5a16b329902f8e543e7b2d7d45f699e4",
 | 
			
		||||
                "sha256:f37495e63607865e47deed08d78f7f8e58172658216ff954b2f14671bcd87740"
 | 
			
		||||
            ],
 | 
			
		||||
            "index": "pypi",
 | 
			
		||||
            "version": "==1.0.8"
 | 
			
		||||
        },
 | 
			
		||||
        "msgpack": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:002a0d813e1f7b60da599bdf969e632074f9eec1b96cbed8fb0973a63160a408",
 | 
			
		||||
                "sha256:0e7b5a69ec5645b0a85baaa354c29acd89eb879aaa89e7f4b37ed4d9c5abafe0",
 | 
			
		||||
                "sha256:25b3bc3190f3d9d965b818123b7752c5dfb953f0d774b454fd206c18fe384fb8",
 | 
			
		||||
                "sha256:271b489499a43af001a2e42f42d876bb98ccaa7e20512ff37ca78c8e12e68f84",
 | 
			
		||||
                "sha256:39c54fdebf5fa4dda733369012c59e7d085ebdfe35b6cf648f09d16708f1be5d",
 | 
			
		||||
                "sha256:4233b7f86c1208190c78a525cd3828ca1623359ef48f78a6fea4b91bb995775a",
 | 
			
		||||
                "sha256:5bea44181fc8e18eed1d0cd76e355073f00ce232ff9653a0ae88cb7d9e643322",
 | 
			
		||||
                "sha256:5dba6d074fac9b24f29aaf1d2d032306c27f04187651511257e7831733293ec2",
 | 
			
		||||
                "sha256:71604047feea609ad65f5b837ec89a4de084d55a80f8af7331745a075c3dbd23",
 | 
			
		||||
                "sha256:7a22c965588baeb07242cb561b63f309db27a07382825fc98aecaf0827c1538e",
 | 
			
		||||
                "sha256:908944e3f038bca67fcfedb7845c4a257c7749bf9818632586b53bcf06ba4b97",
 | 
			
		||||
                "sha256:9534d5cc480d4aff720233411a1f765be90885750b07df772380b34c10ecb5c0",
 | 
			
		||||
                "sha256:aa5c057eab4f40ec47ea6f5a9825846be2ff6bf34102c560bad5cad5a677c5be",
 | 
			
		||||
                "sha256:b3758dfd3423e358bbb18a7cccd1c74228dffa7a697e5be6cb9535de625c0dbf",
 | 
			
		||||
                "sha256:c901e8058dd6653307906c5f157f26ed09eb94a850dddd989621098d347926ab",
 | 
			
		||||
                "sha256:cec8bf10981ed70998d98431cd814db0ecf3384e6b113366e7f36af71a0fca08",
 | 
			
		||||
                "sha256:db685187a415f51d6b937257474ca72199f393dad89534ebbdd7d7a3b000080e",
 | 
			
		||||
                "sha256:e35b051077fc2f3ce12e7c6a34cf309680c63a842db3a0616ea6ed25ad20d272",
 | 
			
		||||
                "sha256:e7bbdd8e2b277b77782f3ce34734b0dfde6cbe94ddb74de8d733d603c7f9e2b1",
 | 
			
		||||
                "sha256:ea41c9219c597f1d2bf6b374d951d310d58684b5de9dc4bd2976db9e1e22c140",
 | 
			
		||||
                "sha256:f7c80ff32171193f18a127ea357118b920020cc0acb0730016bbda02b892a2d2"
 | 
			
		||||
            ],
 | 
			
		||||
            "version": "==1.0.0"
 | 
			
		||||
        },
 | 
			
		||||
        "numpy": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:08308c38e44cc926bdfce99498b21eec1f848d24c302519e64203a8da99a97db",
 | 
			
		||||
@@ -472,6 +218,7 @@
 | 
			
		||||
                "sha256:2fb113757a369a6cdb189f8df3226e995acfed0a8919a72416626af1a0a71140",
 | 
			
		||||
                "sha256:4b0ef2470c4979e345e4e0cc1bbac65fda11d0d7b789dbac035e4c6ce3f98adb",
 | 
			
		||||
                "sha256:59e903ca800c8cfd1ebe482349ec7c35687b95e98cefae213e271c8c7fffa021",
 | 
			
		||||
                "sha256:5a3342d34289715928c914ee7f389351eb37fa4857caa9297fc7948f2ed3e53d",
 | 
			
		||||
                "sha256:5abd653a23c35d980b332bc0431d39663b1709d64142e3652890df4c9b6970f6",
 | 
			
		||||
                "sha256:5f9403af9c790cc18411ea398a6950ee2def2a830ad0cfe6dc9122e6d528b302",
 | 
			
		||||
                "sha256:6b4a8fd632b4ebee28282a9fef4c341835a1aa8671e2770b6f89adc8e8c2703c",
 | 
			
		||||
@@ -529,8 +276,10 @@
 | 
			
		||||
                "sha256:d14b140a4439d816e3b1229a4a525df917d6ea22a0771a2a78332273fd9528a4",
 | 
			
		||||
                "sha256:d1b4ab59e02d9008efe10ceabd0b31e79519da6fb67f7d8e8977118832d0f449",
 | 
			
		||||
                "sha256:d5227b229005a696cc67676e24c214740efd90b148de5733419ac9aaba3773da",
 | 
			
		||||
                "sha256:d9f3a909b59ac4a3ca9beb77716f4bce627276edb039a71d4e9ec4b7548536a0",
 | 
			
		||||
                "sha256:e1f57aa70d3f7cc6947fd88636a481638263ba04a742b4a37dd25c373e41491a",
 | 
			
		||||
                "sha256:e74a55f6bad0e7d3968399deb50f61f4db1926acf4a6d83beaaa7df986f48b1c",
 | 
			
		||||
                "sha256:e7f5a465c6431c0ad8d4e69603ee3306e521a09d3c6af76a16bdb62946bdddf0",
 | 
			
		||||
                "sha256:e82aba2188b9ba309fd8e271702bd0d0fc9148ae3150532bbb474f4590039ffb",
 | 
			
		||||
                "sha256:ee69dad2c7155756ad114c02db06002f4cded41132cc51378e57aad79cc8e4f4",
 | 
			
		||||
                "sha256:f5ab93a2cb2d8338b1674be43b442a7f544a0971da062a5da774ed40587f18f5"
 | 
			
		||||
@@ -538,72 +287,14 @@
 | 
			
		||||
            "index": "pypi",
 | 
			
		||||
            "version": "==2.8.6"
 | 
			
		||||
        },
 | 
			
		||||
        "pyasn1": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359",
 | 
			
		||||
                "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576",
 | 
			
		||||
                "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf",
 | 
			
		||||
                "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7",
 | 
			
		||||
                "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d",
 | 
			
		||||
                "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00",
 | 
			
		||||
                "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8",
 | 
			
		||||
                "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86",
 | 
			
		||||
                "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12",
 | 
			
		||||
                "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776",
 | 
			
		||||
                "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba",
 | 
			
		||||
                "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2",
 | 
			
		||||
                "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"
 | 
			
		||||
            ],
 | 
			
		||||
            "version": "==0.4.8"
 | 
			
		||||
        },
 | 
			
		||||
        "pyasn1-modules": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8",
 | 
			
		||||
                "sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199",
 | 
			
		||||
                "sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811",
 | 
			
		||||
                "sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed",
 | 
			
		||||
                "sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4",
 | 
			
		||||
                "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e",
 | 
			
		||||
                "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74",
 | 
			
		||||
                "sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb",
 | 
			
		||||
                "sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45",
 | 
			
		||||
                "sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd",
 | 
			
		||||
                "sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0",
 | 
			
		||||
                "sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d",
 | 
			
		||||
                "sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405"
 | 
			
		||||
            ],
 | 
			
		||||
            "version": "==0.2.8"
 | 
			
		||||
        },
 | 
			
		||||
        "pycparser": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0",
 | 
			
		||||
                "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"
 | 
			
		||||
            ],
 | 
			
		||||
            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
 | 
			
		||||
            "version": "==2.20"
 | 
			
		||||
        },
 | 
			
		||||
        "pyhamcrest": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:412e00137858f04bde0729913874a48485665f2d36fe9ee449f26be864af9316",
 | 
			
		||||
                "sha256:7ead136e03655af85069b6f47b23eb7c3e5c221aa9f022a4fbb499f5b7308f29"
 | 
			
		||||
            ],
 | 
			
		||||
            "markers": "python_version >= '3.5'",
 | 
			
		||||
            "version": "==2.0.2"
 | 
			
		||||
        },
 | 
			
		||||
        "pyocr": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:fa15adc7e1cf0d345a2990495fe125a947c6e09a60ddba0256a1c14b2e603179"
 | 
			
		||||
                "sha256:fa15adc7e1cf0d345a2990495fe125a947c6e09a60ddba0256a1c14b2e603179",
 | 
			
		||||
                "sha256:fd602af17b6e21985669aadc058a95f343ff921e962ed4aa6520ded32e4d1301"
 | 
			
		||||
            ],
 | 
			
		||||
            "index": "pypi",
 | 
			
		||||
            "version": "==0.7.2"
 | 
			
		||||
        },
 | 
			
		||||
        "pyopenssl": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:621880965a720b8ece2f1b2f54ea2071966ab00e2970ad2ce11d596102063504",
 | 
			
		||||
                "sha256:9a24494b2602aaf402be5c9e30a0b82d4a5c67528fe8fb475e3f3bc00dd69507"
 | 
			
		||||
            ],
 | 
			
		||||
            "version": "==19.1.0"
 | 
			
		||||
        },
 | 
			
		||||
        "python-dateutil": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
 | 
			
		||||
@@ -630,11 +321,22 @@
 | 
			
		||||
        },
 | 
			
		||||
        "python-levenshtein": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:033a11de5e3d19ea25c9302d11224e1a1898fe5abd23c61c7c360c25195e3eb1"
 | 
			
		||||
                "sha256:033a11de5e3d19ea25c9302d11224e1a1898fe5abd23c61c7c360c25195e3eb1",
 | 
			
		||||
                "sha256:15e26882728c29ccdf74cfc6ac4b49fc22c08b44d152348cb0eb1ec4f3dbf9df",
 | 
			
		||||
                "sha256:3df5e5eb144570ecf5ad38864a2393068798328c7f05e7b167a49391d36a2db1",
 | 
			
		||||
                "sha256:7f049b3ddc4b525bd469febafb98bf5202f789b722e0e4ccbec2ffbe8c07d7b4"
 | 
			
		||||
            ],
 | 
			
		||||
            "index": "pypi",
 | 
			
		||||
            "version": "==0.12.0"
 | 
			
		||||
        },
 | 
			
		||||
        "python-magic": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:356efa93c8899047d1eb7d3eb91e871ba2f5b1376edbaf4cc305e3c872207355",
 | 
			
		||||
                "sha256:b757db2a5289ea3f1ced9e60f072965243ea43a2221430048fd8cacab17be0ce"
 | 
			
		||||
            ],
 | 
			
		||||
            "index": "pypi",
 | 
			
		||||
            "version": "==0.4.18"
 | 
			
		||||
        },
 | 
			
		||||
        "pytz": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:3e6b7dd2d1e0a59084bcee14a17af60c5c562cdc16d828e8eba2e683d3a7e268",
 | 
			
		||||
@@ -645,6 +347,7 @@
 | 
			
		||||
        "redis": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2",
 | 
			
		||||
                "sha256:3f1c7f166fa6c803613eec222224848a80f5e5b9c6af3aa82461506643034a7a",
 | 
			
		||||
                "sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"
 | 
			
		||||
            ],
 | 
			
		||||
            "index": "pypi",
 | 
			
		||||
@@ -652,54 +355,55 @@
 | 
			
		||||
        },
 | 
			
		||||
        "regex": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:03855ee22980c3e4863dc84c42d6d2901133362db5daf4c36b710dd895d78f0a",
 | 
			
		||||
                "sha256:06b52815d4ad38d6524666e0d50fe9173533c9cc145a5779b89733284e6f688f",
 | 
			
		||||
                "sha256:11116d424734fe356d8777f89d625f0df783251ada95d6261b4c36ad27a394bb",
 | 
			
		||||
                "sha256:119e0355dbdd4cf593b17f2fc5dbd4aec2b8899d0057e4957ba92f941f704bf5",
 | 
			
		||||
                "sha256:127a9e0c0d91af572fbb9e56d00a504dbd4c65e574ddda3d45b55722462210de",
 | 
			
		||||
                "sha256:1ec66700a10e3c75f1f92cbde36cca0d3aaee4c73dfa26699495a3a30b09093c",
 | 
			
		||||
                "sha256:227a8d2e5282c2b8346e7f68aa759e0331a0b4a890b55a5cfbb28bd0261b84c0",
 | 
			
		||||
                "sha256:2564def9ce0710d510b1fc7e5178ce2d20f75571f788b5197b3c8134c366f50c",
 | 
			
		||||
                "sha256:297116e79074ec2a2f885d22db00ce6e88b15f75162c5e8b38f66ea734e73c64",
 | 
			
		||||
                "sha256:2dc522e25e57e88b4980d2bdd334825dbf6fa55f28a922fc3bfa60cc09e5ef53",
 | 
			
		||||
                "sha256:3a5f08039eee9ea195a89e180c5762bfb55258bfb9abb61a20d3abee3b37fd12",
 | 
			
		||||
                "sha256:3dfca201fa6b326239e1bccb00b915e058707028809b8ecc0cf6819ad233a740",
 | 
			
		||||
                "sha256:49461446b783945597c4076aea3f49aee4b4ce922bd241e4fcf62a3e7c61794c",
 | 
			
		||||
                "sha256:4afa350f162551cf402bfa3cd8302165c8e03e689c897d185f16a167328cc6dd",
 | 
			
		||||
                "sha256:4b5a9bcb56cc146c3932c648603b24514447eafa6ce9295234767bf92f69b504",
 | 
			
		||||
                "sha256:52e83a5f28acd621ba8e71c2b816f6541af7144b69cc5859d17da76c436a5427",
 | 
			
		||||
                "sha256:625116aca6c4b57c56ea3d70369cacc4d62fead4930f8329d242e4fe7a58ce4b",
 | 
			
		||||
                "sha256:654c1635f2313d0843028487db2191530bca45af61ca85d0b16555c399625b0e",
 | 
			
		||||
                "sha256:8092a5a06ad9a7a247f2a76ace121183dc4e1a84c259cf9c2ce3bbb69fac3582",
 | 
			
		||||
                "sha256:832339223b9ce56b7b15168e691ae654d345ac1635eeb367ade9ecfe0e66bee0",
 | 
			
		||||
                "sha256:8ca9dca965bd86ea3631b975d63b0693566d3cc347e55786d5514988b6f5b84c",
 | 
			
		||||
                "sha256:96f99219dddb33e235a37283306834700b63170d7bb2a1ee17e41c6d589c8eb9",
 | 
			
		||||
                "sha256:9b6305295b6591e45f069d3553c54d50cc47629eb5c218aac99e0f7fafbf90a1",
 | 
			
		||||
                "sha256:a62162be05edf64f819925ea88d09d18b09bebf20971b363ce0c24e8b4aa14c0",
 | 
			
		||||
                "sha256:aacc8623ffe7999a97935eeabbd24b1ae701d08ea8f874a6ff050e93c3e658cf",
 | 
			
		||||
                "sha256:b45bab9f224de276b7bc916f6306b86283f6aa8afe7ed4133423efb42015a898",
 | 
			
		||||
                "sha256:b88fa3b8a3469f22b4f13d045d9bd3eda797aa4e406fde0a2644bc92bbdd4bdd",
 | 
			
		||||
                "sha256:b8a686a6c98872007aa41fdbb2e86dc03b287d951ff4a7f1da77fb7f14113e4d",
 | 
			
		||||
                "sha256:bd904c0dec29bbd0769887a816657491721d5f545c29e30fd9d7a1a275dc80ab",
 | 
			
		||||
                "sha256:bf4f896c42c63d1f22039ad57de2644c72587756c0cfb3cc3b7530cfe228277f",
 | 
			
		||||
                "sha256:c13d311a4c4a8d671f5860317eb5f09591fbe8259676b86a85769423b544451e",
 | 
			
		||||
                "sha256:c2c6c56ee97485a127555c9595c069201b5161de9d05495fbe2132b5ac104786",
 | 
			
		||||
                "sha256:c32c91a0f1ac779cbd73e62430de3d3502bbc45ffe5bb6c376015acfa848144b",
 | 
			
		||||
                "sha256:c3466a84fce42c2016113101018a9981804097bacbab029c2d5b4fcb224b89de",
 | 
			
		||||
                "sha256:c454ad88e56e80e44f824ef8366bb7e4c3def12999151fd5c0ea76a18fe9aa3e",
 | 
			
		||||
                "sha256:c8a2b7ccff330ae4c460aff36626f911f918555660cc28163417cb84ffb25789",
 | 
			
		||||
                "sha256:cb905f3d2e290a8b8f1579d3984f2cfa7c3a29cc7cba608540ceeed18513f520",
 | 
			
		||||
                "sha256:cfcf28ed4ce9ced47b9b9670a4f0d3d3c0e4d4779ad4dadb1ad468b097f808aa",
 | 
			
		||||
                "sha256:dd3e6547ecf842a29cf25123fbf8d2461c53c8d37aa20d87ecee130c89b7079b",
 | 
			
		||||
                "sha256:de7fd57765398d141949946c84f3590a68cf5887dac3fc52388df0639b01eda4",
 | 
			
		||||
                "sha256:ea37320877d56a7f0a1e6a625d892cf963aa7f570013499f5b8d5ab8402b5625",
 | 
			
		||||
                "sha256:f1fce1e4929157b2afeb4bb7069204d4370bab9f4fc03ca1fbec8bd601f8c87d",
 | 
			
		||||
                "sha256:f43109822df2d3faac7aad79613f5f02e4eab0fc8ad7932d2e70e2a83bd49c26"
 | 
			
		||||
                "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538",
 | 
			
		||||
                "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4",
 | 
			
		||||
                "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc",
 | 
			
		||||
                "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa",
 | 
			
		||||
                "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444",
 | 
			
		||||
                "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1",
 | 
			
		||||
                "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af",
 | 
			
		||||
                "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8",
 | 
			
		||||
                "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9",
 | 
			
		||||
                "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88",
 | 
			
		||||
                "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba",
 | 
			
		||||
                "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364",
 | 
			
		||||
                "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e",
 | 
			
		||||
                "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7",
 | 
			
		||||
                "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0",
 | 
			
		||||
                "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31",
 | 
			
		||||
                "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683",
 | 
			
		||||
                "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee",
 | 
			
		||||
                "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b",
 | 
			
		||||
                "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884",
 | 
			
		||||
                "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c",
 | 
			
		||||
                "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e",
 | 
			
		||||
                "sha256:80ef188c0e47a6c964eed71c55a73c245f8daf9f0a4a9d804e91275afb468ca4",
 | 
			
		||||
                "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562",
 | 
			
		||||
                "sha256:842fb985b2b99a82a2b145b6bbd588c5f5cfd83693402920fcb985d515794666",
 | 
			
		||||
                "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85",
 | 
			
		||||
                "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c",
 | 
			
		||||
                "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6",
 | 
			
		||||
                "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d",
 | 
			
		||||
                "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b",
 | 
			
		||||
                "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70",
 | 
			
		||||
                "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b",
 | 
			
		||||
                "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b",
 | 
			
		||||
                "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f",
 | 
			
		||||
                "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0",
 | 
			
		||||
                "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5",
 | 
			
		||||
                "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5",
 | 
			
		||||
                "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f",
 | 
			
		||||
                "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e",
 | 
			
		||||
                "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512",
 | 
			
		||||
                "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d",
 | 
			
		||||
                "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917",
 | 
			
		||||
                "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"
 | 
			
		||||
            ],
 | 
			
		||||
            "version": "==2020.10.28"
 | 
			
		||||
            "version": "==2020.11.13"
 | 
			
		||||
        },
 | 
			
		||||
        "scikit-learn": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:090bbf144fd5823c1f2efa3e1a9bf180295b24294ca8f478e75b40ed54f8036e",
 | 
			
		||||
                "sha256:0a127cc70990d4c15b1019680bfedc7fec6c23d14d3719fdf9b64b22d37cdeca",
 | 
			
		||||
                "sha256:0d39748e7c9669ba648acf40fb3ce96b8a07b240db6888563a7cb76e05e0d9cc",
 | 
			
		||||
                "sha256:1b8a391de95f6285a2f9adffb7db0892718950954b7149a70c783dc848f104ea",
 | 
			
		||||
@@ -752,13 +456,6 @@
 | 
			
		||||
            "markers": "python_version >= '3.6'",
 | 
			
		||||
            "version": "==1.5.4"
 | 
			
		||||
        },
 | 
			
		||||
        "service-identity": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:001c0707759cb3de7e49c078a7c0c9cd12594161d3bf06b9c254fdcb1a60dc36",
 | 
			
		||||
                "sha256:0858a54aabc5b459d1aafa8a518ed2081a285087f349fe3e55197989232e2e2d"
 | 
			
		||||
            ],
 | 
			
		||||
            "version": "==18.1.0"
 | 
			
		||||
        },
 | 
			
		||||
        "six": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259",
 | 
			
		||||
@@ -783,48 +480,6 @@
 | 
			
		||||
            "markers": "python_version >= '3.5'",
 | 
			
		||||
            "version": "==2.1.0"
 | 
			
		||||
        },
 | 
			
		||||
        "twisted": {
 | 
			
		||||
            "extras": [
 | 
			
		||||
                "tls"
 | 
			
		||||
            ],
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:0150dae5adc962d15e00054cc6926f1e64763fb8dd26e1632593ac06e592104b",
 | 
			
		||||
                "sha256:040eb6641125d2a9a09cf198ec7b83dd8858c6f51f6770325ed9959c00f5098f",
 | 
			
		||||
                "sha256:147780b8caf21ba2aef3688628eaf13d7e7fe02a86747cd54bfaf2140538f042",
 | 
			
		||||
                "sha256:158ddb80719a4813d292293ac44ba41d8b56555ed009d90994a278237ee63d2c",
 | 
			
		||||
                "sha256:15e52271f08f62e2230ff093e0278aa01c9dac057c4557cadadd2429eed86a3e",
 | 
			
		||||
                "sha256:2182000d6ffc05d269e6c03bfcec8b57e20259ca1086180edaedec3f1e689292",
 | 
			
		||||
                "sha256:25ffcf37944bdad4a99981bc74006d735a678d2b5c193781254fbbb6d69e3b22",
 | 
			
		||||
                "sha256:3281d9ce889f7b21bdb73658e887141aa45a102baf3b2320eafcfba954fcefec",
 | 
			
		||||
                "sha256:356e8d8dd3590e790e3dba4db139eb8a17aca64b46629c622e1b1597a4a92478",
 | 
			
		||||
                "sha256:70952c56e4965b9f53b180daecf20a9595cf22b8d0935cd3bd664c90273c3ab2",
 | 
			
		||||
                "sha256:7408c6635ee1b96587289283ebe90ee15dbf9614b05857b446055116bc822d29",
 | 
			
		||||
                "sha256:7c547fd0215db9da8a1bc23182b309e84a232364cc26d829e9ee196ce840b114",
 | 
			
		||||
                "sha256:894f6f3cfa57a15ea0d0714e4283913a5f2511dbd18653dd148eba53b3919797",
 | 
			
		||||
                "sha256:94ac3d55a58c90e2075c5fe1853f2aa3892b73e3bf56395f743aefde8605eeaa",
 | 
			
		||||
                "sha256:a58e61a2a01e5bcbe3b575c0099a2bcb8d70a75b1a087338e0c48dd6e01a5f15",
 | 
			
		||||
                "sha256:c09c47ff9750a8e3aa60ad169c4b95006d455a29b80ad0901f031a103b2991cd",
 | 
			
		||||
                "sha256:ca3a0b8c9110800e576d89b5337373e52018b41069bc879f12fa42b7eb2d0274",
 | 
			
		||||
                "sha256:cd1dc5c85b58494138a3917752b54bb1daa0045d234b7c132c37a61d5483ebad",
 | 
			
		||||
                "sha256:cdbc4c7f0cd7a2218b575844e970f05a1be1861c607b0e048c9bceca0c4d42f7",
 | 
			
		||||
                "sha256:d267125cc0f1e8a0eed6319ba4ac7477da9b78a535601c49ecd20c875576433a",
 | 
			
		||||
                "sha256:d72c55b5d56e176563b91d11952d13b01af8725c623e498db5507b6614fc1e10",
 | 
			
		||||
                "sha256:d95803193561a243cb0401b0567c6b7987d3f2a67046770e1dccd1c9e49a9780",
 | 
			
		||||
                "sha256:e92703bed0cc21d6cb5c61d66922b3b1564015ca8a51325bd164a5e33798d504",
 | 
			
		||||
                "sha256:f058bd0168271de4dcdc39845b52dd0a4a2fecf5f1246335f13f5e96eaebb467",
 | 
			
		||||
                "sha256:f3c19e5bd42bbe4bf345704ad7c326c74d3fd7a1b3844987853bef180be638d4"
 | 
			
		||||
            ],
 | 
			
		||||
            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
 | 
			
		||||
            "version": "==20.3.0"
 | 
			
		||||
        },
 | 
			
		||||
        "txaio": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:17938f2bca4a9cabce61346758e482ca4e600160cbc28e861493eac74a19539d",
 | 
			
		||||
                "sha256:38a469daf93c37e5527cb062653d6393ae11663147c42fab7ddc3f6d00d434ae"
 | 
			
		||||
            ],
 | 
			
		||||
            "markers": "python_version >= '3.5'",
 | 
			
		||||
            "version": "==20.4.1"
 | 
			
		||||
        },
 | 
			
		||||
        "tzlocal": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:643c97c5294aedc737780a49d9df30889321cbe1204eac2c2ec6134035a92e44",
 | 
			
		||||
@@ -834,6 +489,7 @@
 | 
			
		||||
        },
 | 
			
		||||
        "watchdog": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:034c85530b647486e8c8477410fe79476511282658f2ce496f97106d9e5acfb8",
 | 
			
		||||
                "sha256:4214e1379d128b0588021880ccaf40317ee156d4603ac388b9adcf29165e0c04"
 | 
			
		||||
            ],
 | 
			
		||||
            "index": "pypi",
 | 
			
		||||
@@ -862,66 +518,6 @@
 | 
			
		||||
            ],
 | 
			
		||||
            "index": "pypi",
 | 
			
		||||
            "version": "==2.7.4"
 | 
			
		||||
        },
 | 
			
		||||
        "zope.interface": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:05a97ba92c1c7c26f25c9f671aa1ef85ffead6cdad13770e5b689cf983adc7e1",
 | 
			
		||||
                "sha256:07d61722dd7d85547b7c6b0f5486b4338001fab349f2ac5cabc0b7182eb3425d",
 | 
			
		||||
                "sha256:09fc3922f235703c0b76f8234867685eee68a24a49fffa2220975f6142db45f1",
 | 
			
		||||
                "sha256:0a990dcc97806e5980bbb54b2e46b9cde9e48932d8e6984daf71ef1745516123",
 | 
			
		||||
                "sha256:150e8bcb7253a34a4535aeea3de36c0bb3b1a6a47a183a95d65a194b3e07f232",
 | 
			
		||||
                "sha256:1743bcfe45af8846b775086471c28258f4c6e9ee8ef37484de4495f15a98b549",
 | 
			
		||||
                "sha256:1b5f6c8fff4ed32aa2dd43e84061bc8346f32d3ba6ad6e58f088fe109608f102",
 | 
			
		||||
                "sha256:21e49123f375703cf824214939d39df0af62c47d122d955b2a8d9153ea08cfd5",
 | 
			
		||||
                "sha256:21f579134a47083ffb5ddd1307f0405c91aa8b61ad4be6fd5af0171474fe0c45",
 | 
			
		||||
                "sha256:27c267dc38a0f0079e96a2945ee65786d38ef111e413c702fbaaacbab6361d00",
 | 
			
		||||
                "sha256:299bde0ab9e5c4a92f01a152b7fbabb460f31343f1416f9b7b983167ab1e33bc",
 | 
			
		||||
                "sha256:2ab88d8f228f803fcb8cb7d222c579d13dab2d3622c51e8cf321280da01102a7",
 | 
			
		||||
                "sha256:2ced4c35061eea623bc84c7711eedce8ecc3c2c51cd9c6afa6290df3bae9e104",
 | 
			
		||||
                "sha256:2dcab01c660983ba5e5a612e0c935141ccbee67d2e2e14b833e01c2354bd8034",
 | 
			
		||||
                "sha256:32546af61a9a9b141ca38d971aa6eb9800450fa6620ce6323cc30eec447861f3",
 | 
			
		||||
                "sha256:32b40a4c46d199827d79c86bb8cb88b1bbb764f127876f2cb6f3a47f63dbada3",
 | 
			
		||||
                "sha256:3cc94c69f6bd48ed86e8e24f358cb75095c8129827df1298518ab860115269a4",
 | 
			
		||||
                "sha256:42b278ac0989d6f5cf58d7e0828ea6b5951464e3cf2ff229dd09a96cb6ba0c86",
 | 
			
		||||
                "sha256:495b63fd0302f282ee6c1e6ea0f1c12cb3d1a49c8292d27287f01845ff252a96",
 | 
			
		||||
                "sha256:4af87cdc0d4b14e600e6d3d09793dce3b7171348a094ba818e2a68ae7ee67546",
 | 
			
		||||
                "sha256:4b94df9f2fdde7b9314321bab8448e6ad5a23b80542dcab53e329527d4099dcb",
 | 
			
		||||
                "sha256:4c48ddb63e2b20fba4c6a2bf81b4d49e99b6d4587fb67a6cd33a2c1f003af3e3",
 | 
			
		||||
                "sha256:4df9afd17bd5477e9f8c8b6bb8507e18dd0f8b4efe73bb99729ff203279e9e3b",
 | 
			
		||||
                "sha256:518950fe6a5d56f94ba125107895f938a4f34f704c658986eae8255edb41163b",
 | 
			
		||||
                "sha256:538298e4e113ccb8b41658d5a4b605bebe75e46a30ceca22a5a289cf02c80bec",
 | 
			
		||||
                "sha256:55465121e72e208a7b69b53de791402affe6165083b2ea71b892728bd19ba9ae",
 | 
			
		||||
                "sha256:588384d70a0f19b47409cfdb10e0c27c20e4293b74fc891df3d8eb47782b8b3e",
 | 
			
		||||
                "sha256:6278c080d4afffc9016e14325f8734456831124e8c12caa754fd544435c08386",
 | 
			
		||||
                "sha256:64ea6c221aeee4796860405e1aedec63424cda4202a7ad27a5066876db5b0fd2",
 | 
			
		||||
                "sha256:681dbb33e2b40262b33fd383bae63c36d33fd79fa1a8e4092945430744ffd34a",
 | 
			
		||||
                "sha256:6936aa9da390402d646a32a6a38d5409c2d2afb2950f045a7d02ab25a4e7d08d",
 | 
			
		||||
                "sha256:778d0ec38bbd288b150a3ae363c8ffd88d2207a756842495e9bffd8a8afbc89a",
 | 
			
		||||
                "sha256:8251f06a77985a2729a8bdbefbae79ee78567dddc3acbd499b87e705ca59fe24",
 | 
			
		||||
                "sha256:83b4aa5344cce005a9cff5d0321b2e318e871cc1dfc793b66c32dd4f59e9770d",
 | 
			
		||||
                "sha256:844fad925ac5c2ad4faaceb3b2520ad016b5280105c6e16e79838cf951903a7b",
 | 
			
		||||
                "sha256:8ceb3667dd13b8133f2e4d637b5b00f240f066448e2aa89a41f4c2d78a26ce50",
 | 
			
		||||
                "sha256:92dc0fb79675882d0b6138be4bf0cec7ea7c7eede60aaca78303d8e8dbdaa523",
 | 
			
		||||
                "sha256:974f5957e66a7524ea81df7b2686a456bfaf0408dbb7353ddfbedb594eadfef6",
 | 
			
		||||
                "sha256:9789bd945e9f5bd026ed3f5b453d640befb8b1fc33a779c1fe8d3eb21fe3fb4a",
 | 
			
		||||
                "sha256:a2b6d6eb693bc2fc6c484f2e5d93bd0b0da803fa77bf974f160533e555e4d095",
 | 
			
		||||
                "sha256:aab9f1e34d810feb00bf841993552b8fcc6ae71d473c505381627143d0018a6a",
 | 
			
		||||
                "sha256:abb61afd84f23099ac6099d804cdba9bd3b902aaaded3ffff47e490b0a495520",
 | 
			
		||||
                "sha256:adf9ee115ae8ff8b6da4b854b4152f253b390ba64407a22d75456fe07dcbda65",
 | 
			
		||||
                "sha256:aedc6c672b351afe6dfe17ff83ee5e7eb6ed44718f879a9328a68bdb20b57e11",
 | 
			
		||||
                "sha256:b7a00ecb1434f8183395fac5366a21ee73d14900082ca37cf74993cf46baa56c",
 | 
			
		||||
                "sha256:ba32f4a91c1cb7314c429b03afbf87b1fff4fb1c8db32260e7310104bd77f0c7",
 | 
			
		||||
                "sha256:cbd0f2cbd8689861209cd89141371d3a22a11613304d1f0736492590aa0ab332",
 | 
			
		||||
                "sha256:e4bc372b953bf6cec65a8d48482ba574f6e051621d157cf224227dbb55486b1e",
 | 
			
		||||
                "sha256:eccac3d9aadc68e994b6d228cb0c8919fc47a5350d85a1b4d3d81d1e98baf40c",
 | 
			
		||||
                "sha256:efd550b3da28195746bb43bd1d815058181a7ca6d9d6aa89dd37f5eefe2cacb7",
 | 
			
		||||
                "sha256:efef581c8ba4d990770875e1a2218e856849d32ada2680e53aebc5d154a17e20",
 | 
			
		||||
                "sha256:f057897711a630a0b7a6a03f1acf379b6ba25d37dc5dc217a97191984ba7f2fc",
 | 
			
		||||
                "sha256:f37d45fab14ffef9d33a0dc3bc59ce0c5313e2253323312d47739192da94f5fd",
 | 
			
		||||
                "sha256:f44906f70205d456d503105023041f1e63aece7623b31c390a0103db4de17537"
 | 
			
		||||
            ],
 | 
			
		||||
            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
 | 
			
		||||
            "version": "==5.2.0"
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    "develop": {
 | 
			
		||||
@@ -1021,11 +617,11 @@
 | 
			
		||||
        },
 | 
			
		||||
        "coveralls": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:4430b862baabb3cf090d36d84d331966615e4288d8a8c5957e0fd456d0dd8bd6",
 | 
			
		||||
                "sha256:b3b60c17b03a0dee61952a91aed6f131e0b2ac8bd5da909389c53137811409e1"
 | 
			
		||||
                "sha256:2301a19500b06649d2ec4f2858f9c69638d7699a4c63027c5d53daba666147cc",
 | 
			
		||||
                "sha256:b990ba1f7bc4288e63340be0433698c1efe8217f78c689d254c2540af3d38617"
 | 
			
		||||
            ],
 | 
			
		||||
            "index": "pypi",
 | 
			
		||||
            "version": "==2.1.2"
 | 
			
		||||
            "version": "==2.2.0"
 | 
			
		||||
        },
 | 
			
		||||
        "distlib": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
@@ -1230,6 +826,7 @@
 | 
			
		||||
        },
 | 
			
		||||
        "pytest-env": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:33b4030383a021924fe3f3ba5ca4311990d8b1d02ca77389c2be020c4500f96a",
 | 
			
		||||
                "sha256:7e94956aef7f2764f3c147d216ce066bf6c42948bb9e293169b1b1c880a580c2"
 | 
			
		||||
            ],
 | 
			
		||||
            "index": "pypi",
 | 
			
		||||
@@ -1246,6 +843,7 @@
 | 
			
		||||
        },
 | 
			
		||||
        "pytest-sugar": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:67a55a83c7b2717ad607704d3fe9004bb6543b54017ef82f9c6590acc38c1aec",
 | 
			
		||||
                "sha256:b1b2186b0a72aada6859bea2a5764145e3aaa2c1cfbb23c3a19b5f7b697563d3"
 | 
			
		||||
            ],
 | 
			
		||||
            "index": "pypi",
 | 
			
		||||
@@ -1299,11 +897,11 @@
 | 
			
		||||
        },
 | 
			
		||||
        "sphinx": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
                "sha256:1c21e7c5481a31b531e6cbf59c3292852ccde175b504b00ce2ff0b8f4adc3649",
 | 
			
		||||
                "sha256:3abdb2c57a65afaaa4f8573cbabd5465078eb6fd282c1e4f87f006875a7ec0c7"
 | 
			
		||||
                "sha256:1e8d592225447104d1172be415bc2972bd1357e3e12fdc76edf2261105db4300",
 | 
			
		||||
                "sha256:d4e59ad4ea55efbb3c05cde3bfc83bfc14f0c95aa95c3d75346fcce186a47960"
 | 
			
		||||
            ],
 | 
			
		||||
            "index": "pypi",
 | 
			
		||||
            "version": "==3.3.0"
 | 
			
		||||
            "version": "==3.3.1"
 | 
			
		||||
        },
 | 
			
		||||
        "sphinx-rtd-theme": {
 | 
			
		||||
            "hashes": [
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
[](https://travis-ci.org/jonaswinkler/paperless-ng)
 | 
			
		||||
[](https://paperless-ng.readthedocs.io/en/latest/?badge=latest)
 | 
			
		||||
[](https://hub.docker.com/r/jonaswinkler/paperless-ng)
 | 
			
		||||
[](https://coveralls.io/github/jonaswinkler/paperless-ng?branch=master)
 | 
			
		||||
 | 
			
		||||
# Paperless-ng
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,8 +15,42 @@ map_uidgid() {
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
wait_for_postgres() {
 | 
			
		||||
	attempt_num=1
 | 
			
		||||
	max_attempts=5
 | 
			
		||||
 | 
			
		||||
	echo "Waiting for PostgreSQL to start..."
 | 
			
		||||
 | 
			
		||||
	host="${PAPERLESS_DBHOST}"
 | 
			
		||||
 | 
			
		||||
	while !</dev/tcp/$host/5432 ;
 | 
			
		||||
	do
 | 
			
		||||
 | 
			
		||||
		if [ $attempt_num -eq $max_attempts ]
 | 
			
		||||
		then
 | 
			
		||||
			echo "Unable to connect to database."
 | 
			
		||||
			exit 1
 | 
			
		||||
		else
 | 
			
		||||
			echo "Attempt $attempt_num failed! Trying again in 5 seconds..."
 | 
			
		||||
 | 
			
		||||
		fi
 | 
			
		||||
 | 
			
		||||
		attempt_num=$(expr "$attempt_num" + 1)
 | 
			
		||||
		sleep 5
 | 
			
		||||
	done
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
migrations() {
 | 
			
		||||
 | 
			
		||||
	if [[ -n "${PAPERLESS_DBHOST}" ]]
 | 
			
		||||
	then
 | 
			
		||||
		wait_for_postgres
 | 
			
		||||
	fi
 | 
			
		||||
 | 
			
		||||
	(
 | 
			
		||||
		# flock is in place to prevent multiple containers from doing migrations
 | 
			
		||||
		# simultaneously. This also ensures that the db is ready when the command
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,33 @@
 | 
			
		||||
Changelog
 | 
			
		||||
*********
 | 
			
		||||
 | 
			
		||||
next
 | 
			
		||||
####
 | 
			
		||||
 | 
			
		||||
* Paperless now uses mime types and libmagic detection to determine
 | 
			
		||||
  if a file type is supported and which parser to use. Removes all
 | 
			
		||||
  file type checks that where present in MANY different places in
 | 
			
		||||
  paperless.
 | 
			
		||||
 | 
			
		||||
* Mail consumer now correctly consumes documents even when their
 | 
			
		||||
  content type was not set correctly. (i.e. PDF documents with
 | 
			
		||||
  content type ``application/octet-stream``)
 | 
			
		||||
 | 
			
		||||
* Docker entrypoint script awaits the database server if it is
 | 
			
		||||
  configured.
 | 
			
		||||
 | 
			
		||||
* Basic sorting of mail rules added.
 | 
			
		||||
 | 
			
		||||
* Disabled editing of logs.
 | 
			
		||||
 | 
			
		||||
* Much better admin for mail rule editing.
 | 
			
		||||
 | 
			
		||||
* New setting ``PAPERLESS_OCR_PAGES`` limits the tesseract parser
 | 
			
		||||
  to the first n pages of scanned documents.
 | 
			
		||||
 | 
			
		||||
* Fixed a bug where tasks with too long task names would not show 
 | 
			
		||||
  up in the admin.
 | 
			
		||||
 | 
			
		||||
paperless-ng 0.9.1
 | 
			
		||||
##################
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -184,6 +184,16 @@ PAPERLESS_TIME_ZONE=<timezone>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
PAPERLESS_OCR_PAGES=<num>
 | 
			
		||||
    Tells paperless to use only the specified amount of pages for OCR. Documents
 | 
			
		||||
    with less than the specified amount of pages get OCR'ed completely.
 | 
			
		||||
 | 
			
		||||
    Specifying 1 here will only use the first page.
 | 
			
		||||
 | 
			
		||||
    Defaults to 0, which disables this feature and always uses all pages.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
PAPERLESS_OCR_LANGUAGE=<lang>
 | 
			
		||||
    Customize the default language that tesseract will attempt to use when
 | 
			
		||||
    parsing documents. The default language is used whenever
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								docs/faq.rst
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								docs/faq.rst
									
									
									
									
									
								
							@@ -21,6 +21,17 @@ is
 | 
			
		||||
    files around manually. This folder is meant to be entirely managed by docker
 | 
			
		||||
    and paperless.
 | 
			
		||||
 | 
			
		||||
**Q:** *What file types does paperless-ng support?*
 | 
			
		||||
 | 
			
		||||
**A:** Currently, the following files are supported:
 | 
			
		||||
 | 
			
		||||
*   PDF documents, PNG images and JPEG images are processed with OCR.
 | 
			
		||||
*   Plain text documents are supported as well and are added verbatim
 | 
			
		||||
    to paperless.
 | 
			
		||||
 | 
			
		||||
Paperless determines the type of a file by inspecting its content. The
 | 
			
		||||
file extensions do not matter.
 | 
			
		||||
 | 
			
		||||
**Q:** *Will paperless-ng run on Raspberry Pi?*
 | 
			
		||||
 | 
			
		||||
**A:** The short answer is yes. I've tested it on a Raspberry Pi 3 B.
 | 
			
		||||
 
 | 
			
		||||
@@ -44,6 +44,9 @@ resources in the documentation:
 | 
			
		||||
    that's fully tested and production ready.
 | 
			
		||||
*   See :ref:`this note <utilities-encyption>` about GnuPG encryption in
 | 
			
		||||
    paperless-ng.
 | 
			
		||||
*   Paperless is now integrated with a
 | 
			
		||||
    :ref:`task processing queue <setup-task_processor>` that tells you
 | 
			
		||||
    at a glance when and why something is not working. 
 | 
			
		||||
*   The :ref:`changelog <paperless_changelog>` contains a detailed list of all changes
 | 
			
		||||
    in paperless-ng.
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										135
									
								
								docs/setup.rst
									
									
									
									
									
								
							
							
						
						
									
										135
									
								
								docs/setup.rst
									
									
									
									
									
								
							@@ -10,10 +10,10 @@ Go to the project page on GitHub and download the
 | 
			
		||||
`latest release <https://github.com/jonaswinkler/paperless-ng/releases>`_.
 | 
			
		||||
There are multiple options available.
 | 
			
		||||
 | 
			
		||||
*   Download the docker-compose files if you want to pull paperless from
 | 
			
		||||
*   Download the dockerfiles archive if you want to pull paperless from
 | 
			
		||||
    Docker Hub.
 | 
			
		||||
 | 
			
		||||
*   Download the archive and extract it if you want to build the docker image
 | 
			
		||||
*   Download the dist archive and extract it if you want to build the docker image
 | 
			
		||||
    yourself or want to install paperless without docker.
 | 
			
		||||
 | 
			
		||||
.. hint::
 | 
			
		||||
@@ -22,6 +22,15 @@ There are multiple options available.
 | 
			
		||||
    is not to pull the entire git repository. Paperless-ng includes artifacts
 | 
			
		||||
    that need to be compiled, and that's already done for you in the release.
 | 
			
		||||
 | 
			
		||||
.. admonition:: Want to try out paperless-ng before migrating?
 | 
			
		||||
 | 
			
		||||
    The release contains a file ``.env`` which sets the docker-compose project
 | 
			
		||||
    name to "paperless", which is the same as before and instructs docker-compose
 | 
			
		||||
    to reuse and upgrade your paperless volumes.
 | 
			
		||||
 | 
			
		||||
    Just rename the project name in that file to anything else and docker-compose
 | 
			
		||||
    will create fresh volumes for you!
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Overview of Paperless-ng
 | 
			
		||||
########################
 | 
			
		||||
@@ -57,6 +66,8 @@ Paperless consists of the following components:
 | 
			
		||||
        $ cd /path/to/paperless/src/
 | 
			
		||||
        $ pipenv run python3 manage.py document_consumer
 | 
			
		||||
 | 
			
		||||
    .. _setup-task_processor:
 | 
			
		||||
 | 
			
		||||
*   **The task processor:** Paperless relies on `Django Q <https://django-q.readthedocs.io/en/latest/>`_
 | 
			
		||||
    for doing much of the heavy lifting. This is a task queue that accepts tasks from
 | 
			
		||||
    multiple sources and processes tasks in parallel. It also comes with a scheduler that executes
 | 
			
		||||
@@ -77,7 +88,8 @@ Paperless consists of the following components:
 | 
			
		||||
    a modern multicore system, consumption with full ocr is blazing fast.
 | 
			
		||||
 | 
			
		||||
    The task processor comes with a built-in admin interface that you can use to see whenever any of the
 | 
			
		||||
    tasks fail and inspect the errors.
 | 
			
		||||
    tasks fail and inspect the errors (i.e., wrong email credentials, errors during consuming a specific
 | 
			
		||||
    file, etc).
 | 
			
		||||
 | 
			
		||||
    You may start the task processor by executing:
 | 
			
		||||
 | 
			
		||||
@@ -240,15 +252,21 @@ Migration to paperless-ng is then performed in a few simple steps:
 | 
			
		||||
 | 
			
		||||
    .. caution::
 | 
			
		||||
 | 
			
		||||
        Make sure you also download the ``.env`` file. This will set the
 | 
			
		||||
        project name for docker compose to ``paperless`` and then it will
 | 
			
		||||
        automatically reuse your existing paperless volumes.
 | 
			
		||||
        The release include a ``.env`` file. This will set the
 | 
			
		||||
        project name for docker compose to ``paperless`` so that paperless-ng will
 | 
			
		||||
        automatically reuse your existing paperless volumes. When you start it, it
 | 
			
		||||
        will migrate your existing data. After that, your old paperless installation
 | 
			
		||||
        will be incompatible with the migrated volumes.
 | 
			
		||||
 | 
			
		||||
4.  Adjust ``docker-compose.yml`` and
 | 
			
		||||
4.  Copy the ``docker-compose.sqlite.yml`` file to ``docker-compose.yml``.
 | 
			
		||||
    If you want to migrate to PostgreSQL, do that after you migrated your existing
 | 
			
		||||
    SQLite database.
 | 
			
		||||
 | 
			
		||||
5.  Adjust ``docker-compose.yml`` and
 | 
			
		||||
    ``docker-compose.env`` to your needs.
 | 
			
		||||
    See `docker route`_ for details on which edits are required.
 | 
			
		||||
    See `docker route`_ for details on which edits are advised.
 | 
			
		||||
 | 
			
		||||
5.  Start paperless-ng.
 | 
			
		||||
6.  Start paperless-ng.
 | 
			
		||||
 | 
			
		||||
    .. code:: bash
 | 
			
		||||
 | 
			
		||||
@@ -264,19 +282,106 @@ Migration to paperless-ng is then performed in a few simple steps:
 | 
			
		||||
 | 
			
		||||
    This will run paperless in the background and automatically start it on system boot.
 | 
			
		||||
 | 
			
		||||
6.  Paperless installed a permanent redirect to ``admin/`` in your browser. This
 | 
			
		||||
7.  Paperless installed a permanent redirect to ``admin/`` in your browser. This
 | 
			
		||||
    redirect is still in place and prevents access to the new UI. Clear
 | 
			
		||||
    everything related to paperless in your browsers data in order to fix
 | 
			
		||||
    this issue.
 | 
			
		||||
    browsing cache in order to fix this.
 | 
			
		||||
 | 
			
		||||
8.  Optionally, follow the instructions below to migrate your existing data to PostgreSQL.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.. _setup-sqlite_to_psql:
 | 
			
		||||
 | 
			
		||||
Moving data from sqlite to postgresql
 | 
			
		||||
Moving data from SQLite to PostgreSQL
 | 
			
		||||
=====================================
 | 
			
		||||
 | 
			
		||||
.. warning::
 | 
			
		||||
Moving your data from SQLite to PostgreSQL is done via executing a series of django
 | 
			
		||||
management commands as below.
 | 
			
		||||
 | 
			
		||||
.. caution::
 | 
			
		||||
 | 
			
		||||
    Make sure that your sqlite database is migrated to the latest version.
 | 
			
		||||
    Starting paperless will make sure that this is the case. If your try to
 | 
			
		||||
    load data from an old database schema in SQLite into a newer database
 | 
			
		||||
    schema in PostgreSQL, you will run into trouble.
 | 
			
		||||
 | 
			
		||||
1.  Stop paperless, if it is running.
 | 
			
		||||
2.  Tell paperless to use PostgreSQL:
 | 
			
		||||
 | 
			
		||||
    a)  With docker, copy the provided ``docker-compose.postgres.yml`` file to
 | 
			
		||||
        ``docker-compose.yml``. Remember to adjust the consumption directory,
 | 
			
		||||
        if necessary.
 | 
			
		||||
    b)  Without docker, configure the database in your ``paperless.conf`` file.
 | 
			
		||||
        See :ref:`configuration` for details.
 | 
			
		||||
 | 
			
		||||
3.  Open a shell and initialize the database:
 | 
			
		||||
 | 
			
		||||
    a)  With docker, run the following command to open a shell within the paperless
 | 
			
		||||
        container:
 | 
			
		||||
 | 
			
		||||
        .. code:: shell-session
 | 
			
		||||
 | 
			
		||||
            $ cd /path/to/paperless
 | 
			
		||||
            $ docker-compose run --rm webserver /bin/bash
 | 
			
		||||
        
 | 
			
		||||
        This will lauch the container and initialize the PostgreSQL database.
 | 
			
		||||
    
 | 
			
		||||
    b)  Without docker, open a shell in your virtual environment, switch to
 | 
			
		||||
        the ``src`` directory and create the database schema:
 | 
			
		||||
 | 
			
		||||
        .. code:: shell-session
 | 
			
		||||
 | 
			
		||||
            $ cd /path/to/paperless
 | 
			
		||||
            $ pipenv shell
 | 
			
		||||
            $ cd src
 | 
			
		||||
            $ python3 manage.py migrate
 | 
			
		||||
        
 | 
			
		||||
        This will not copy any data yet.
 | 
			
		||||
 | 
			
		||||
4.  Dump your data from SQLite:
 | 
			
		||||
 | 
			
		||||
    .. code:: shell-session
 | 
			
		||||
 | 
			
		||||
        $ python3 manage.py dumpdata --database=sqlite --exclude=contenttypes --exclude=auth.Permission > data.json
 | 
			
		||||
    
 | 
			
		||||
5.  Load your data into PostgreSQL:
 | 
			
		||||
 | 
			
		||||
    .. code:: shell-session
 | 
			
		||||
 | 
			
		||||
        $ python3 manage.py loaddata data.json
 | 
			
		||||
 | 
			
		||||
6.  Exit the shell.
 | 
			
		||||
 | 
			
		||||
    .. code:: shell-session
 | 
			
		||||
 | 
			
		||||
        $ exit
 | 
			
		||||
 | 
			
		||||
7.  Start paperless.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Considerations for less powerful devices
 | 
			
		||||
########################################
 | 
			
		||||
 | 
			
		||||
Paperless runs on Raspberry Pi. However, some things are rather slow on the Pi and 
 | 
			
		||||
configuring some options in paperless can help improve performance immensely:
 | 
			
		||||
 | 
			
		||||
*   Consider setting ``PAPERLESS_OCR_PAGES`` to 1, so that paperless will only OCR
 | 
			
		||||
    the first page of your documents.
 | 
			
		||||
*   ``PAPERLESS_TASK_WORKERS`` and ``PAPERLESS_THREADS_PER_WORKER`` are configured
 | 
			
		||||
    to use all cores. The Raspberry Pi models 3 and up have 4 cores, meaning that
 | 
			
		||||
    paperless will use 2 workers and 2 threads per worker. This may result in
 | 
			
		||||
    slugish response times during consumption, so you might want to lower these
 | 
			
		||||
    settings (example: 2 workers and 1 thread to always have some computing power
 | 
			
		||||
    left for other tasks).
 | 
			
		||||
*   Keep ``PAPERLESS_OCR_ALWAYS`` at its default value 'false' and consider OCR'ing
 | 
			
		||||
    your documents before feeding them into paperless. Some scanners are able to
 | 
			
		||||
    do this!
 | 
			
		||||
*   Lower ``PAPERLESS_CONVERT_DENSITY`` from its default value 300 to 200. This
 | 
			
		||||
    will still result in rather accurate OCR, but will decrease consumption time
 | 
			
		||||
    by quite a bit.
 | 
			
		||||
*   Set ``PAPERLESS_OPTIMIZE_THUMBNAILS`` to 'false' if you want faster consumption
 | 
			
		||||
    times. Thumbnails will be about 20% larger.
 | 
			
		||||
 | 
			
		||||
For details, refer to :ref:`configuration`.
 | 
			
		||||
 | 
			
		||||
    TBD.
 | 
			
		||||
 | 
			
		||||
.. _redis: https://redis.io/
 | 
			
		||||
 
 | 
			
		||||
@@ -35,6 +35,7 @@
 | 
			
		||||
#PAPERLESS_TASK_WORKERS=1
 | 
			
		||||
#PAPERLESS_THREADS_PER_WORKER=1
 | 
			
		||||
#PAPERLESS_TIME_ZONE=UTC
 | 
			
		||||
#PAPERLESS_OCR_PAGES=1
 | 
			
		||||
#PAPERLESS_OCR_LANGUAGE=eng
 | 
			
		||||
#PAPERLESS_OCR_ALWAYS=false
 | 
			
		||||
#PAPERLESS_CONSUMER_POLLING=10
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@ PAPERLESS_ROOT=$(git rev-parse --show-toplevel)
 | 
			
		||||
# output directory
 | 
			
		||||
PAPERLESS_DIST="$PAPERLESS_ROOT/dist"
 | 
			
		||||
PAPERLESS_DIST_APP="$PAPERLESS_DIST/paperless-ng"
 | 
			
		||||
PAPERLESS_DIST_DOCKERFILES="$PAPERLESS_DIST/paperless-ng-dockerfiles"
 | 
			
		||||
 | 
			
		||||
if [ -d "$PAPERLESS_DIST" ]
 | 
			
		||||
then
 | 
			
		||||
@@ -27,6 +28,7 @@ fi
 | 
			
		||||
mkdir "$PAPERLESS_DIST"
 | 
			
		||||
mkdir "$PAPERLESS_DIST_APP"
 | 
			
		||||
mkdir "$PAPERLESS_DIST_APP/docker"
 | 
			
		||||
mkdir "$PAPERLESS_DIST_DOCKERFILES"
 | 
			
		||||
 | 
			
		||||
# setup dependencies.
 | 
			
		||||
 | 
			
		||||
@@ -78,9 +80,9 @@ cp "$PAPERLESS_ROOT/docker/local/"* "$PAPERLESS_DIST_APP"
 | 
			
		||||
cp "$PAPERLESS_ROOT/docker/docker-compose.env" "$PAPERLESS_DIST_APP"
 | 
			
		||||
 | 
			
		||||
# docker files for pulling from docker hub
 | 
			
		||||
cp "$PAPERLESS_ROOT/docker/hub/"* "$PAPERLESS_DIST"
 | 
			
		||||
cp "$PAPERLESS_ROOT/.env" "$PAPERLESS_DIST"
 | 
			
		||||
cp "$PAPERLESS_ROOT/docker/docker-compose.env" "$PAPERLESS_DIST"
 | 
			
		||||
cp "$PAPERLESS_ROOT/docker/hub/"* "$PAPERLESS_DIST_DOCKERFILES"
 | 
			
		||||
cp "$PAPERLESS_ROOT/.env" "$PAPERLESS_DIST_DOCKERFILES"
 | 
			
		||||
cp "$PAPERLESS_ROOT/docker/docker-compose.env" "$PAPERLESS_DIST_DOCKERFILES"
 | 
			
		||||
 | 
			
		||||
# auxiliary files required for the docker image
 | 
			
		||||
cp "$PAPERLESS_ROOT/docker/docker-entrypoint.sh" "$PAPERLESS_DIST_APP/docker/"
 | 
			
		||||
@@ -99,3 +101,4 @@ docker build . -t "jonaswinkler/paperless-ng:$VERSION"
 | 
			
		||||
cd "$PAPERLESS_DIST"
 | 
			
		||||
 | 
			
		||||
tar -cJf "paperless-ng-$VERSION.tar.xz" paperless-ng/
 | 
			
		||||
tar -cJf "paperless-ng-$VERSION-dockerfiles.tar.xz" paperless-ng-dockerfiles/
 | 
			
		||||
 
 | 
			
		||||
@@ -1,126 +1,130 @@
 | 
			
		||||
{
 | 
			
		||||
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
 | 
			
		||||
  "version": 1,
 | 
			
		||||
  "newProjectRoot": "projects",
 | 
			
		||||
  "projects": {
 | 
			
		||||
    "paperless-ui": {
 | 
			
		||||
      "projectType": "application",
 | 
			
		||||
      "schematics": {},
 | 
			
		||||
      "root": "",
 | 
			
		||||
      "sourceRoot": "src",
 | 
			
		||||
      "prefix": "app",
 | 
			
		||||
      "architect": {
 | 
			
		||||
        "build": {
 | 
			
		||||
          "builder": "@angular-devkit/build-angular:browser",
 | 
			
		||||
          "options": {
 | 
			
		||||
            "outputPath": "dist/paperless-ui",
 | 
			
		||||
            "outputHashing": "none",
 | 
			
		||||
            "index": "src/index.html",
 | 
			
		||||
            "main": "src/main.ts",
 | 
			
		||||
            "polyfills": "src/polyfills.ts",
 | 
			
		||||
            "tsConfig": "tsconfig.app.json",
 | 
			
		||||
            "aot": true,
 | 
			
		||||
            "assets": [
 | 
			
		||||
              "src/favicon.ico",
 | 
			
		||||
              "src/assets"
 | 
			
		||||
            ],
 | 
			
		||||
            "styles": [
 | 
			
		||||
              "node_modules/bootstrap/dist/css/bootstrap.min.css",
 | 
			
		||||
              "src/styles.css"
 | 
			
		||||
            ],
 | 
			
		||||
            "scripts": []
 | 
			
		||||
          },
 | 
			
		||||
          "configurations": {
 | 
			
		||||
            "production": {
 | 
			
		||||
              "fileReplacements": [
 | 
			
		||||
                {
 | 
			
		||||
                  "replace": "src/environments/environment.ts",
 | 
			
		||||
                  "with": "src/environments/environment.prod.ts"
 | 
			
		||||
                }
 | 
			
		||||
              ],
 | 
			
		||||
              "optimization": true,
 | 
			
		||||
              "outputHashing": "none",
 | 
			
		||||
              "sourceMap": false,
 | 
			
		||||
              "extractCss": true,
 | 
			
		||||
              "namedChunks": false,
 | 
			
		||||
              "extractLicenses": true,
 | 
			
		||||
              "vendorChunk": false,
 | 
			
		||||
              "buildOptimizer": true,
 | 
			
		||||
              "budgets": [
 | 
			
		||||
                {
 | 
			
		||||
                  "type": "initial",
 | 
			
		||||
                  "maximumWarning": "2mb",
 | 
			
		||||
                  "maximumError": "5mb"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                  "type": "anyComponentStyle",
 | 
			
		||||
                  "maximumWarning": "6kb",
 | 
			
		||||
                  "maximumError": "10kb"
 | 
			
		||||
                }
 | 
			
		||||
              ]
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "serve": {
 | 
			
		||||
          "builder": "@angular-devkit/build-angular:dev-server",
 | 
			
		||||
          "options": {
 | 
			
		||||
            "browserTarget": "paperless-ui:build"
 | 
			
		||||
          },
 | 
			
		||||
          "configurations": {
 | 
			
		||||
            "production": {
 | 
			
		||||
              "browserTarget": "paperless-ui:build:production"
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "extract-i18n": {
 | 
			
		||||
          "builder": "@angular-devkit/build-angular:extract-i18n",
 | 
			
		||||
          "options": {
 | 
			
		||||
            "browserTarget": "paperless-ui:build"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "test": {
 | 
			
		||||
          "builder": "@angular-devkit/build-angular:karma",
 | 
			
		||||
          "options": {
 | 
			
		||||
            "main": "src/test.ts",
 | 
			
		||||
            "polyfills": "src/polyfills.ts",
 | 
			
		||||
            "tsConfig": "tsconfig.spec.json",
 | 
			
		||||
            "karmaConfig": "karma.conf.js",
 | 
			
		||||
            "assets": [
 | 
			
		||||
              "src/favicon.ico",
 | 
			
		||||
              "src/assets"
 | 
			
		||||
            ],
 | 
			
		||||
            "styles": [
 | 
			
		||||
              "src/styles.css"
 | 
			
		||||
            ],
 | 
			
		||||
            "scripts": []
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "lint": {
 | 
			
		||||
          "builder": "@angular-devkit/build-angular:tslint",
 | 
			
		||||
          "options": {
 | 
			
		||||
            "tsConfig": [
 | 
			
		||||
              "tsconfig.app.json",
 | 
			
		||||
              "tsconfig.spec.json",
 | 
			
		||||
              "e2e/tsconfig.json"
 | 
			
		||||
            ],
 | 
			
		||||
            "exclude": [
 | 
			
		||||
              "**/node_modules/**"
 | 
			
		||||
            ]
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "e2e": {
 | 
			
		||||
          "builder": "@angular-devkit/build-angular:protractor",
 | 
			
		||||
          "options": {
 | 
			
		||||
            "protractorConfig": "e2e/protractor.conf.js",
 | 
			
		||||
            "devServerTarget": "paperless-ui:serve"
 | 
			
		||||
          },
 | 
			
		||||
          "configurations": {
 | 
			
		||||
            "production": {
 | 
			
		||||
              "devServerTarget": "paperless-ui:serve:production"
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }},
 | 
			
		||||
  "defaultProject": "paperless-ui"
 | 
			
		||||
}
 | 
			
		||||
	"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
 | 
			
		||||
	"version": 1,
 | 
			
		||||
	"newProjectRoot": "projects",
 | 
			
		||||
	"projects": {
 | 
			
		||||
		"paperless-ui": {
 | 
			
		||||
			"projectType": "application",
 | 
			
		||||
			"schematics": {
 | 
			
		||||
				"@schematics/angular:component": {
 | 
			
		||||
					"style": "scss"
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			"root": "",
 | 
			
		||||
			"sourceRoot": "src",
 | 
			
		||||
			"prefix": "app",
 | 
			
		||||
			"architect": {
 | 
			
		||||
				"build": {
 | 
			
		||||
					"builder": "@angular-devkit/build-angular:browser",
 | 
			
		||||
					"options": {
 | 
			
		||||
						"outputPath": "dist/paperless-ui",
 | 
			
		||||
						"outputHashing": "none",
 | 
			
		||||
						"index": "src/index.html",
 | 
			
		||||
						"main": "src/main.ts",
 | 
			
		||||
						"polyfills": "src/polyfills.ts",
 | 
			
		||||
						"tsConfig": "tsconfig.app.json",
 | 
			
		||||
						"aot": true,
 | 
			
		||||
						"assets": [
 | 
			
		||||
							"src/favicon.ico",
 | 
			
		||||
							"src/assets"
 | 
			
		||||
						],
 | 
			
		||||
						"styles": [
 | 
			
		||||
							"src/styles.scss"
 | 
			
		||||
						],
 | 
			
		||||
						"scripts": []
 | 
			
		||||
					},
 | 
			
		||||
					"configurations": {
 | 
			
		||||
						"production": {
 | 
			
		||||
							"fileReplacements": [
 | 
			
		||||
								{
 | 
			
		||||
									"replace": "src/environments/environment.ts",
 | 
			
		||||
									"with": "src/environments/environment.prod.ts"
 | 
			
		||||
								}
 | 
			
		||||
							],
 | 
			
		||||
							"optimization": true,
 | 
			
		||||
							"outputHashing": "none",
 | 
			
		||||
							"sourceMap": false,
 | 
			
		||||
							"extractCss": true,
 | 
			
		||||
							"namedChunks": false,
 | 
			
		||||
							"extractLicenses": true,
 | 
			
		||||
							"vendorChunk": false,
 | 
			
		||||
							"buildOptimizer": true,
 | 
			
		||||
							"budgets": [
 | 
			
		||||
								{
 | 
			
		||||
									"type": "initial",
 | 
			
		||||
									"maximumWarning": "2mb",
 | 
			
		||||
									"maximumError": "5mb"
 | 
			
		||||
								},
 | 
			
		||||
								{
 | 
			
		||||
									"type": "anyComponentStyle",
 | 
			
		||||
									"maximumWarning": "6kb",
 | 
			
		||||
									"maximumError": "10kb"
 | 
			
		||||
								}
 | 
			
		||||
							]
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				"serve": {
 | 
			
		||||
					"builder": "@angular-devkit/build-angular:dev-server",
 | 
			
		||||
					"options": {
 | 
			
		||||
						"browserTarget": "paperless-ui:build"
 | 
			
		||||
					},
 | 
			
		||||
					"configurations": {
 | 
			
		||||
						"production": {
 | 
			
		||||
							"browserTarget": "paperless-ui:build:production"
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				"extract-i18n": {
 | 
			
		||||
					"builder": "@angular-devkit/build-angular:extract-i18n",
 | 
			
		||||
					"options": {
 | 
			
		||||
						"browserTarget": "paperless-ui:build"
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				"test": {
 | 
			
		||||
					"builder": "@angular-devkit/build-angular:karma",
 | 
			
		||||
					"options": {
 | 
			
		||||
						"main": "src/test.ts",
 | 
			
		||||
						"polyfills": "src/polyfills.ts",
 | 
			
		||||
						"tsConfig": "tsconfig.spec.json",
 | 
			
		||||
						"karmaConfig": "karma.conf.js",
 | 
			
		||||
						"assets": [
 | 
			
		||||
							"src/favicon.ico",
 | 
			
		||||
							"src/assets"
 | 
			
		||||
						],
 | 
			
		||||
						"styles": [
 | 
			
		||||
							"src/styles.scss"
 | 
			
		||||
						],
 | 
			
		||||
						"scripts": []
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				"lint": {
 | 
			
		||||
					"builder": "@angular-devkit/build-angular:tslint",
 | 
			
		||||
					"options": {
 | 
			
		||||
						"tsConfig": [
 | 
			
		||||
							"tsconfig.app.json",
 | 
			
		||||
							"tsconfig.spec.json",
 | 
			
		||||
							"e2e/tsconfig.json"
 | 
			
		||||
						],
 | 
			
		||||
						"exclude": [
 | 
			
		||||
							"**/node_modules/**"
 | 
			
		||||
						]
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				"e2e": {
 | 
			
		||||
					"builder": "@angular-devkit/build-angular:protractor",
 | 
			
		||||
					"options": {
 | 
			
		||||
						"protractorConfig": "e2e/protractor.conf.js",
 | 
			
		||||
						"devServerTarget": "paperless-ui:serve"
 | 
			
		||||
					},
 | 
			
		||||
					"configurations": {
 | 
			
		||||
						"production": {
 | 
			
		||||
							"devServerTarget": "paperless-ui:serve:production"
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"defaultProject": "paperless-ui"
 | 
			
		||||
}
 | 
			
		||||
@@ -7,7 +7,7 @@ import { Toast, ToastService } from './services/toast.service';
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-root',
 | 
			
		||||
  templateUrl: './app.component.html',
 | 
			
		||||
  styleUrls: ['./app.component.css']
 | 
			
		||||
  styleUrls: ['./app.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class AppComponent implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -42,9 +42,9 @@ import { SortableDirective } from './directives/sortable.directive';
 | 
			
		||||
import { CookieService } from 'ngx-cookie-service';
 | 
			
		||||
import { CsrfInterceptor } from './interceptors/csrf.interceptor';
 | 
			
		||||
import { SavedViewWidgetComponent } from './components/dashboard/widgets/saved-view-widget/saved-view-widget.component';
 | 
			
		||||
import { ConsumerStatusWidgetComponent } from './components/dashboard/widgets/consumer-status-widget/consumer-status-widget.component';
 | 
			
		||||
import { StatisticsWidgetComponent } from './components/dashboard/widgets/statistics-widget/statistics-widget.component';
 | 
			
		||||
import { FileUploadWidgetComponent } from './components/dashboard/widgets/file-upload-widget/file-upload-widget.component';
 | 
			
		||||
import { UploadFileWidgetComponent } from './components/dashboard/widgets/upload-file-widget/upload-file-widget.component';
 | 
			
		||||
import { WidgetFrameComponent } from './components/dashboard/widgets/widget-frame/widget-frame.component';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  declarations: [
 | 
			
		||||
@@ -79,10 +79,10 @@ import { FileUploadWidgetComponent } from './components/dashboard/widgets/file-u
 | 
			
		||||
    DateTimeComponent,
 | 
			
		||||
    TagsComponent,
 | 
			
		||||
    SortableDirective,
 | 
			
		||||
    ConsumerStatusWidgetComponent,
 | 
			
		||||
    SavedViewWidgetComponent,
 | 
			
		||||
    StatisticsWidgetComponent,
 | 
			
		||||
    FileUploadWidgetComponent
 | 
			
		||||
    UploadFileWidgetComponent,
 | 
			
		||||
    WidgetFrameComponent
 | 
			
		||||
  ],
 | 
			
		||||
  imports: [
 | 
			
		||||
    BrowserModule,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,32 +1,26 @@
 | 
			
		||||
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0 shadow">
 | 
			
		||||
  <span class="navbar-brand col-md-3 col-lg-2 mr-0 px-3" href="#">Paperless-ng</span>
 | 
			
		||||
<nav class="navbar navbar-dark sticky-top bg-primary flex-md-nowrap p-0 shadow">
 | 
			
		||||
  <span class="navbar-brand col-md-3 col-lg-2 mr-0 px-3" href="#">
 | 
			
		||||
    <img src="assets/logo-dark-notext.svg" height="18px" class="mr-2">
 | 
			
		||||
    Paperless-ng
 | 
			
		||||
  </span>
 | 
			
		||||
  <button class="navbar-toggler position-absolute d-md-none collapsed" type="button" data-toggle="collapse"
 | 
			
		||||
    data-target="#sidebarMenu" aria-controls="sidebarMenu" aria-expanded="false" aria-label="Toggle navigation">
 | 
			
		||||
    data-target="#sidebarMenu" aria-controls="sidebarMenu" aria-expanded="false" aria-label="Toggle navigation"
 | 
			
		||||
    (click)="isMenuCollapsed = !isMenuCollapsed">
 | 
			
		||||
    <span class="navbar-toggler-icon"></span>
 | 
			
		||||
  </button>
 | 
			
		||||
  <form (ngSubmit)="search()" class="w-100">
 | 
			
		||||
  <form (ngSubmit)="search()" class="w-100 m-1">
 | 
			
		||||
    <input class="form-control form-control-dark" type="text" placeholder="Search" aria-label="Search"
 | 
			
		||||
      [formControl]="searchField" [ngbTypeahead]="searchAutoComplete" (selectItem)="itemSelected($event)">
 | 
			
		||||
  </form>
 | 
			
		||||
  <ul class="navbar-nav px-3">
 | 
			
		||||
    <li class="nav-item text-nowrap">
 | 
			
		||||
      <a class="nav-link" href="accounts/logout/">
 | 
			
		||||
        <svg class="buttonicon" fill="currentColor">
 | 
			
		||||
          <use xlink:href="assets/bootstrap-icons.svg#door-closed"/>
 | 
			
		||||
        </svg>
 | 
			
		||||
        Logout
 | 
			
		||||
      </a>
 | 
			
		||||
    </li>
 | 
			
		||||
  </ul>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<div class="container-fluid">
 | 
			
		||||
  <div class="row">
 | 
			
		||||
    <nav id="sidebarMenu" class="col-md-3 col-lg-2 d-md-block bg-light sidebar collapse">
 | 
			
		||||
    <nav id="sidebarMenu" class="col-md-3 col-lg-2 d-md-block bg-light sidebar collapse" [ngbCollapse]="isMenuCollapsed">
 | 
			
		||||
      <div class="sidebar-sticky pt-3">
 | 
			
		||||
        <ul class="nav flex-column">
 | 
			
		||||
          <li class="nav-item">
 | 
			
		||||
            <a class="nav-link" routerLink="dashboard" routerLinkActive="active">
 | 
			
		||||
            <a class="nav-link" routerLink="dashboard" routerLinkActive="active" (click)="closeMenu()">
 | 
			
		||||
              <svg class="sidebaricon" fill="currentColor">
 | 
			
		||||
                <use xlink:href="assets/bootstrap-icons.svg#house"/>
 | 
			
		||||
              </svg>
 | 
			
		||||
@@ -34,7 +28,7 @@
 | 
			
		||||
            </a>
 | 
			
		||||
          </li>
 | 
			
		||||
          <li class="nav-item">
 | 
			
		||||
            <a class="nav-link" routerLink="documents" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}">
 | 
			
		||||
            <a class="nav-link" routerLink="documents" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}" (click)="closeMenu()">
 | 
			
		||||
              <svg class="sidebaricon" fill="currentColor">
 | 
			
		||||
                <use xlink:href="assets/bootstrap-icons.svg#files"/>
 | 
			
		||||
              </svg>
 | 
			
		||||
@@ -48,7 +42,7 @@
 | 
			
		||||
        </h6>
 | 
			
		||||
        <ul class="nav flex-column mb-2">
 | 
			
		||||
          <li class="nav-item w-100" *ngFor='let config of viewConfigService.getSideBarConfigs()'>
 | 
			
		||||
            <a class="nav-link text-truncate" routerLink="view/{{config.id}}" routerLinkActive="active">
 | 
			
		||||
            <a class="nav-link text-truncate" routerLink="view/{{config.id}}" routerLinkActive="active" (click)="closeMenu()">
 | 
			
		||||
              <svg class="sidebaricon" fill="currentColor">
 | 
			
		||||
                <use xlink:href="assets/bootstrap-icons.svg#funnel"/>
 | 
			
		||||
              </svg>
 | 
			
		||||
@@ -62,7 +56,7 @@
 | 
			
		||||
        </h6>
 | 
			
		||||
        <ul class="nav flex-column mb-2">
 | 
			
		||||
          <li class="nav-item w-100" *ngFor='let d of openDocuments'>
 | 
			
		||||
            <a class="nav-link text-truncate" routerLink="documents/{{d.id}}" routerLinkActive="active">
 | 
			
		||||
            <a class="nav-link text-truncate" routerLink="documents/{{d.id}}" routerLinkActive="active" (click)="closeMenu()">
 | 
			
		||||
              <svg class="sidebaricon" fill="currentColor">
 | 
			
		||||
                <use xlink:href="assets/bootstrap-icons.svg#file-text"/>
 | 
			
		||||
              </svg>
 | 
			
		||||
@@ -84,7 +78,7 @@
 | 
			
		||||
        </h6>
 | 
			
		||||
        <ul class="nav flex-column mb-2">
 | 
			
		||||
          <li class="nav-item">
 | 
			
		||||
            <a class="nav-link" routerLink="correspondents" routerLinkActive="active">
 | 
			
		||||
            <a class="nav-link" routerLink="correspondents" routerLinkActive="active" (click)="closeMenu()">
 | 
			
		||||
              <svg class="sidebaricon" fill="currentColor">
 | 
			
		||||
                <use xlink:href="assets/bootstrap-icons.svg#person"/>
 | 
			
		||||
              </svg>
 | 
			
		||||
@@ -92,7 +86,7 @@
 | 
			
		||||
            </a>
 | 
			
		||||
          </li>
 | 
			
		||||
          <li class="nav-item">
 | 
			
		||||
            <a class="nav-link" routerLink="tags" routerLinkActive="active">
 | 
			
		||||
            <a class="nav-link" routerLink="tags" routerLinkActive="active" (click)="closeMenu()">
 | 
			
		||||
              <svg class="sidebaricon" fill="currentColor">
 | 
			
		||||
                <use xlink:href="assets/bootstrap-icons.svg#tags"/>
 | 
			
		||||
              </svg>
 | 
			
		||||
@@ -100,7 +94,7 @@
 | 
			
		||||
            </a>
 | 
			
		||||
          </li>
 | 
			
		||||
          <li class="nav-item">
 | 
			
		||||
            <a class="nav-link" routerLink="documenttypes" routerLinkActive="active">
 | 
			
		||||
            <a class="nav-link" routerLink="documenttypes" routerLinkActive="active" (click)="closeMenu()">
 | 
			
		||||
              <svg class="sidebaricon" fill="currentColor">
 | 
			
		||||
                <use xlink:href="assets/bootstrap-icons.svg#hash"/>
 | 
			
		||||
              </svg>
 | 
			
		||||
@@ -108,7 +102,7 @@
 | 
			
		||||
            </a>
 | 
			
		||||
          </li>
 | 
			
		||||
          <li class="nav-item">
 | 
			
		||||
            <a class="nav-link" routerLink="logs" routerLinkActive="active">
 | 
			
		||||
            <a class="nav-link" routerLink="logs" routerLinkActive="active" (click)="closeMenu()">
 | 
			
		||||
              <svg class="sidebaricon" fill="currentColor">
 | 
			
		||||
                <use xlink:href="assets/bootstrap-icons.svg#text-left"/>
 | 
			
		||||
              </svg>
 | 
			
		||||
@@ -116,7 +110,7 @@
 | 
			
		||||
            </a>
 | 
			
		||||
          </li>
 | 
			
		||||
          <li class="nav-item">
 | 
			
		||||
            <a class="nav-link" routerLink="settings" routerLinkActive="active">
 | 
			
		||||
            <a class="nav-link" routerLink="settings" routerLinkActive="active" (click)="closeMenu()">
 | 
			
		||||
              <svg class="sidebaricon" fill="currentColor">
 | 
			
		||||
                <use xlink:href="assets/bootstrap-icons.svg#gear"/>
 | 
			
		||||
              </svg>
 | 
			
		||||
@@ -150,7 +144,15 @@
 | 
			
		||||
              <svg class="sidebaricon" fill="currentColor">
 | 
			
		||||
                <use xlink:href="assets/bootstrap-icons.svg#link"/>
 | 
			
		||||
              </svg>
 | 
			
		||||
              Github
 | 
			
		||||
              GitHub
 | 
			
		||||
            </a>
 | 
			
		||||
          </li>
 | 
			
		||||
          <li class="nav-item">
 | 
			
		||||
            <a class="nav-link" href="accounts/logout/">
 | 
			
		||||
              <svg class="sidebaricon" fill="currentColor">
 | 
			
		||||
                <use xlink:href="assets/bootstrap-icons.svg#door-open"/>
 | 
			
		||||
              </svg>
 | 
			
		||||
              Logout
 | 
			
		||||
            </a>
 | 
			
		||||
          </li>
 | 
			
		||||
        </ul>
 | 
			
		||||
@@ -161,4 +163,4 @@
 | 
			
		||||
      <router-outlet></router-outlet>
 | 
			
		||||
    </main>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,6 @@
 | 
			
		||||
 | 
			
		||||
@import "/src/theme";
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
 * Sidebar
 | 
			
		||||
 */
 | 
			
		||||
@@ -15,14 +17,15 @@
 | 
			
		||||
 | 
			
		||||
@media (max-width: 767.98px) {
 | 
			
		||||
  .sidebar {
 | 
			
		||||
    top: 5rem;
 | 
			
		||||
    top: 3rem;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar-sticky {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  height: calc(100vh - 48px);
 | 
			
		||||
  /* height: calc(100vh - 48px); */
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  padding-top: .5rem;
 | 
			
		||||
  overflow-x: hidden;
 | 
			
		||||
  overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
 | 
			
		||||
@@ -46,7 +49,7 @@
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar .nav-link.active {
 | 
			
		||||
  color: #007bff;
 | 
			
		||||
  color: $primary;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar .nav-link:hover .sidebaricon,
 | 
			
		||||
@@ -12,7 +12,7 @@ import { DocumentDetailComponent } from '../document-detail/document-detail.comp
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-app-frame',
 | 
			
		||||
  templateUrl: './app-frame.component.html',
 | 
			
		||||
  styleUrls: ['./app-frame.component.css']
 | 
			
		||||
  styleUrls: ['./app-frame.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class AppFrameComponent implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
@@ -25,6 +25,12 @@ export class AppFrameComponent implements OnInit, OnDestroy {
 | 
			
		||||
    ) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  isMenuCollapsed: boolean = true
 | 
			
		||||
 | 
			
		||||
  closeMenu() {
 | 
			
		||||
    this.isMenuCollapsed = true
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  searchField = new FormControl('')
 | 
			
		||||
 | 
			
		||||
  openDocuments: PaperlessDocument[] = []
 | 
			
		||||
@@ -61,10 +67,12 @@ export class AppFrameComponent implements OnInit, OnDestroy {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  search() {
 | 
			
		||||
    this.closeMenu()
 | 
			
		||||
    this.router.navigate(['search'], {queryParams: {query: this.searchField.value}})
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  closeAll() {
 | 
			
		||||
    this.closeMenu()
 | 
			
		||||
    this.openDocumentsService.closeAll()
 | 
			
		||||
 | 
			
		||||
    // TODO: is there a better way to do this?
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-delete-dialog',
 | 
			
		||||
  templateUrl: './delete-dialog.component.html',
 | 
			
		||||
  styleUrls: ['./delete-dialog.component.css']
 | 
			
		||||
  styleUrls: ['./delete-dialog.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class DeleteDialogComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<div class="form-group form-check">
 | 
			
		||||
  <input type="checkbox" class="form-check-input" [id]="inputId" [(ngModel)]="value" (change)="onChange(value)" (blur)="onTouched()" [disabled]="disabled">
 | 
			
		||||
  <label class="form-check-label" [for]="inputId">{{title}}</label>
 | 
			
		||||
<div class="form-group custom-control custom-checkbox">
 | 
			
		||||
  <input type="checkbox" class="custom-control-input" [id]="inputId" [(ngModel)]="value" (change)="onChange(value)" (blur)="onTouched()" [disabled]="disabled">
 | 
			
		||||
  <label class="custom-control-label" [for]="inputId">{{title}}</label>
 | 
			
		||||
  <small *ngIf="hint" class="form-text text-muted">{{hint}}</small>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -11,7 +11,7 @@ import { AbstractInputComponent } from '../abstract-input';
 | 
			
		||||
  }],
 | 
			
		||||
  selector: 'app-input-check',
 | 
			
		||||
  templateUrl: './check.component.html',
 | 
			
		||||
  styleUrls: ['./check.component.css']
 | 
			
		||||
  styleUrls: ['./check.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class CheckComponent extends AbstractInputComponent<boolean> {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ import { AbstractInputComponent } from '../abstract-input';
 | 
			
		||||
  }],
 | 
			
		||||
  selector: 'app-input-date-time',
 | 
			
		||||
  templateUrl: './date-time.component.html',
 | 
			
		||||
  styleUrls: ['./date-time.component.css']
 | 
			
		||||
  styleUrls: ['./date-time.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class DateTimeComponent implements OnInit,ControlValueAccessor  {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ import { AbstractInputComponent } from '../abstract-input';
 | 
			
		||||
  }],
 | 
			
		||||
  selector: 'app-input-select',
 | 
			
		||||
  templateUrl: './select.component.html',
 | 
			
		||||
  styleUrls: ['./select.component.css']
 | 
			
		||||
  styleUrls: ['./select.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class SelectComponent extends AbstractInputComponent<number> {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ import { TagService } from 'src/app/services/rest/tag.service';
 | 
			
		||||
  }],
 | 
			
		||||
  selector: 'app-input-tags',
 | 
			
		||||
  templateUrl: './tags.component.html',
 | 
			
		||||
  styleUrls: ['./tags.component.css']
 | 
			
		||||
  styleUrls: ['./tags.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class TagsComponent implements OnInit, ControlValueAccessor {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ import { AbstractInputComponent } from '../abstract-input';
 | 
			
		||||
  }],
 | 
			
		||||
  selector: 'app-input-text',
 | 
			
		||||
  templateUrl: './text.component.html',
 | 
			
		||||
  styleUrls: ['./text.component.css']
 | 
			
		||||
  styleUrls: ['./text.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class TextComponent extends AbstractInputComponent<string> {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
<div class="row pt-3 pb-1 mb-3 border-bottom align-items-center" >
 | 
			
		||||
  <div class="col text-truncate">
 | 
			
		||||
    <h1 class="h2 text-truncate" style="line-height: 1.4">{{title}}</h1>
 | 
			
		||||
  <div class="col-md text-truncate">
 | 
			
		||||
    <p class="h2 text-truncate" style="line-height: 1.4">{{title}}</p>
 | 
			
		||||
    <p *ngIf="subTitle" class="h5 text-truncate" style="line-height: 1.4">{{subTitle}}</p>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="btn-toolbar col-auto">
 | 
			
		||||
    <ng-content></ng-content>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ import { Component, Input, OnInit } from '@angular/core';
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-page-header',
 | 
			
		||||
  templateUrl: './page-header.component.html',
 | 
			
		||||
  styleUrls: ['./page-header.component.css']
 | 
			
		||||
  styleUrls: ['./page-header.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class PageHeaderComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
@@ -12,6 +12,9 @@ export class PageHeaderComponent implements OnInit {
 | 
			
		||||
  @Input()
 | 
			
		||||
  title: string = ""
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  subTitle: string = ""
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ import { TAG_COLOURS, PaperlessTag } from 'src/app/data/paperless-tag';
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-tag',
 | 
			
		||||
  templateUrl: './tag.component.html',
 | 
			
		||||
  styleUrls: ['./tag.component.css']
 | 
			
		||||
  styleUrls: ['./tag.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class TagComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@ import { Toast, ToastService } from 'src/app/services/toast.service';
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-toasts',
 | 
			
		||||
  templateUrl: './toasts.component.html',
 | 
			
		||||
  styleUrls: ['./toasts.component.css']
 | 
			
		||||
  styleUrls: ['./toasts.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class ToastsComponent implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,27 @@
 | 
			
		||||
 | 
			
		||||
<app-page-header title="Dashboard">
 | 
			
		||||
<app-page-header title="Dashboard" subTitle="Welcome to paperless-ng!">
 | 
			
		||||
  <img src="assets/logo.svg" height="80" class="m-2 d-none d-md-block">
 | 
			
		||||
</app-page-header>
 | 
			
		||||
 | 
			
		||||
<p>Welcome to paperless-ng!</p>
 | 
			
		||||
 | 
			
		||||
<div class='row'>
 | 
			
		||||
  <div class="col-lg">
 | 
			
		||||
    <app-saved-view-widget [viewConfig]="conf" *ngFor="let conf of savedViewConfigService.getDashboardConfigs()"></app-saved-view-widget>
 | 
			
		||||
    <app-widget-frame title="Saved views" *ngIf="savedViews.length == 0">
 | 
			
		||||
      <p class="card-text">This space is reserved to display your saved views. Go to your documents and save a view
 | 
			
		||||
        to have it displayed
 | 
			
		||||
        here!</p>
 | 
			
		||||
    </app-widget-frame>
 | 
			
		||||
 | 
			
		||||
    <ng-container *ngFor="let v of savedViews">
 | 
			
		||||
      <app-saved-view-widget [savedView]="v"></app-saved-view-widget>
 | 
			
		||||
    </ng-container>
 | 
			
		||||
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="col-lg">
 | 
			
		||||
 | 
			
		||||
    <app-statistics-widget></app-statistics-widget>
 | 
			
		||||
    <app-file-upload-widget></app-file-upload-widget>
 | 
			
		||||
 | 
			
		||||
    <app-upload-file-widget></app-upload-file-widget>
 | 
			
		||||
 | 
			
		||||
    <app-consumer-status-widget></app-consumer-status-widget>
 | 
			
		||||
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,22 +1,22 @@
 | 
			
		||||
import { HttpClient } from '@angular/common/http';
 | 
			
		||||
import { Component, OnInit } from '@angular/core';
 | 
			
		||||
import { FileSystemFileEntry, NgxFileDropEntry } from 'ngx-file-drop';
 | 
			
		||||
import { Observable } from 'rxjs';
 | 
			
		||||
import { DocumentService } from 'src/app/services/rest/document.service';
 | 
			
		||||
import { SavedViewConfigService } from 'src/app/services/saved-view-config.service';
 | 
			
		||||
import { ToastService } from 'src/app/services/toast.service';
 | 
			
		||||
import { environment } from 'src/environments/environment';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-dashboard',
 | 
			
		||||
  templateUrl: './dashboard.component.html',
 | 
			
		||||
  styleUrls: ['./dashboard.component.css']
 | 
			
		||||
  styleUrls: ['./dashboard.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class DashboardComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
  constructor(public savedViewConfigService: SavedViewConfigService) { }
 | 
			
		||||
  constructor(
 | 
			
		||||
    public savedViewConfigService: SavedViewConfigService) { }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  savedViews = []
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    this.savedViews = this.savedViewConfigService.getDashboardConfigs()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,18 @@
 | 
			
		||||
<h4>{{viewConfig.title}}</h4>
 | 
			
		||||
<app-widget-frame [title]="savedView.title">
 | 
			
		||||
 | 
			
		||||
<table class="table table-sm table-hover table-borderless">
 | 
			
		||||
  <thead>
 | 
			
		||||
  <tr>
 | 
			
		||||
    <th>Date created</th>
 | 
			
		||||
    <th scope="col">Document</th>
 | 
			
		||||
  </tr>
 | 
			
		||||
  </thead>
 | 
			
		||||
  <tbody>
 | 
			
		||||
    <tr *ngFor="let doc of documents" routerLink="/documents/{{doc.id}}">
 | 
			
		||||
      <td>{{doc.created | date}}</td>
 | 
			
		||||
      <td>{{doc.title}}<app-tag [tag]="t" *ngFor="let t of doc.tags" class="ml-1"></app-tag>
 | 
			
		||||
    </tr>
 | 
			
		||||
  </tbody>
 | 
			
		||||
</table>
 | 
			
		||||
  <table class="table table-sm table-hover table-borderless">
 | 
			
		||||
    <thead>
 | 
			
		||||
      <tr>
 | 
			
		||||
        <th>Created</th>
 | 
			
		||||
        <th scope="col">Title</th>
 | 
			
		||||
      </tr>
 | 
			
		||||
    </thead>
 | 
			
		||||
    <tbody>
 | 
			
		||||
      <tr *ngFor="let doc of documents" routerLink="/documents/{{doc.id}}">
 | 
			
		||||
        <td>{{doc.created | date}}</td>
 | 
			
		||||
        <td>{{doc.title}}<app-tag [tag]="t" *ngFor="let t of doc.tags" class="ml-1"></app-tag>
 | 
			
		||||
      </tr>
 | 
			
		||||
    </tbody>
 | 
			
		||||
  </table>
 | 
			
		||||
 | 
			
		||||
</app-widget-frame>
 | 
			
		||||
 
 | 
			
		||||
@@ -8,16 +8,16 @@ import { DocumentService } from 'src/app/services/rest/document.service';
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-saved-view-widget',
 | 
			
		||||
  templateUrl: './saved-view-widget.component.html',
 | 
			
		||||
  styleUrls: ['./saved-view-widget.component.css']
 | 
			
		||||
  styleUrls: ['./saved-view-widget.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class SavedViewWidgetComponent implements OnInit, OnDestroy {
 | 
			
		||||
export class SavedViewWidgetComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
  constructor(private documentService: DocumentService, private consumerStatusService: ConsumerStatusService) { }
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  viewConfig: SavedViewConfig
 | 
			
		||||
  savedView: SavedViewConfig
 | 
			
		||||
 | 
			
		||||
  documents: PaperlessDocument[]
 | 
			
		||||
  documents: PaperlessDocument[] = []
 | 
			
		||||
 | 
			
		||||
  subscription: Subscription
 | 
			
		||||
 | 
			
		||||
@@ -33,7 +33,7 @@ export class SavedViewWidgetComponent implements OnInit, OnDestroy {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  reload() {
 | 
			
		||||
    this.documentService.list(1,10,this.viewConfig.sortField,this.viewConfig.sortDirection,this.viewConfig.filterRules).subscribe(result => {
 | 
			
		||||
    this.documentService.list(1,10,this.savedView.sortField,this.savedView.sortDirection,this.savedView.filterRules).subscribe(result => {
 | 
			
		||||
      this.documents = result.results
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
<h4>Statistics</h4>
 | 
			
		||||
<p>Documents in inbox: {{statistics.documents_inbox}}</p>
 | 
			
		||||
<p>Total documents: {{statistics.documents_total}}</p>
 | 
			
		||||
<app-widget-frame title="Statistics">
 | 
			
		||||
  <p class="card-text">Documents in inbox: {{statistics.documents_inbox}}</p>
 | 
			
		||||
  <p class="card-text">Total documents: {{statistics.documents_total}}</p>
 | 
			
		||||
</app-widget-frame>
 | 
			
		||||
 
 | 
			
		||||
@@ -8,10 +8,11 @@ export interface Statistics {
 | 
			
		||||
  documents_inbox?: number
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-statistics-widget',
 | 
			
		||||
  templateUrl: './statistics-widget.component.html',
 | 
			
		||||
  styleUrls: ['./statistics-widget.component.css']
 | 
			
		||||
  styleUrls: ['./statistics-widget.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class StatisticsWidgetComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
@@ -19,14 +20,14 @@ export class StatisticsWidgetComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
  statistics: Statistics = {}
 | 
			
		||||
 | 
			
		||||
  getStatistics(): Observable<Statistics> {
 | 
			
		||||
    return this.http.get(`${environment.apiBaseUrl}statistics/`)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    this.getStatistics().subscribe(statistics => {
 | 
			
		||||
      this.statistics = statistics
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getStatistics(): Observable<Statistics> {
 | 
			
		||||
    return this.http.get(`${environment.apiBaseUrl}statistics/`)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,15 @@
 | 
			
		||||
<app-widget-frame title="Upload new documents">
 | 
			
		||||
 | 
			
		||||
  <form>
 | 
			
		||||
    <ngx-file-drop 
 | 
			
		||||
      dropZoneLabel="Drop documents here or" (onFileDrop)="dropped($event)"
 | 
			
		||||
      (onFileOver)="fileOver($event)" (onFileLeave)="fileLeave($event)"
 | 
			
		||||
      dropZoneClassName="bg-light card"
 | 
			
		||||
      multiple="true"
 | 
			
		||||
      contentClassName="justify-content-center d-flex align-items-center p-5"
 | 
			
		||||
      [showBrowseBtn]=true
 | 
			
		||||
      browseBtnClassName="btn btn-sm btn-outline-primary ml-2">
 | 
			
		||||
 | 
			
		||||
    </ngx-file-drop>
 | 
			
		||||
  </form>
 | 
			
		||||
</app-widget-frame>
 | 
			
		||||
@@ -0,0 +1,25 @@
 | 
			
		||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
 | 
			
		||||
 | 
			
		||||
import { UploadFileWidgetComponent } from './upload-file-widget.component';
 | 
			
		||||
 | 
			
		||||
describe('UploadFileWidgetComponent', () => {
 | 
			
		||||
  let component: UploadFileWidgetComponent;
 | 
			
		||||
  let fixture: ComponentFixture<UploadFileWidgetComponent>;
 | 
			
		||||
 | 
			
		||||
  beforeEach(async () => {
 | 
			
		||||
    await TestBed.configureTestingModule({
 | 
			
		||||
      declarations: [ UploadFileWidgetComponent ]
 | 
			
		||||
    })
 | 
			
		||||
    .compileComponents();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  beforeEach(() => {
 | 
			
		||||
    fixture = TestBed.createComponent(UploadFileWidgetComponent);
 | 
			
		||||
    component = fixture.componentInstance;
 | 
			
		||||
    fixture.detectChanges();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should create', () => {
 | 
			
		||||
    expect(component).toBeTruthy();
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,44 @@
 | 
			
		||||
import { Component, OnInit } from '@angular/core';
 | 
			
		||||
import { FileSystemFileEntry, NgxFileDropEntry } from 'ngx-file-drop';
 | 
			
		||||
import { DocumentService } from 'src/app/services/rest/document.service';
 | 
			
		||||
import { Toast, ToastService } from 'src/app/services/toast.service';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-upload-file-widget',
 | 
			
		||||
  templateUrl: './upload-file-widget.component.html',
 | 
			
		||||
  styleUrls: ['./upload-file-widget.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class UploadFileWidgetComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
  constructor(private documentService: DocumentService, private toastService: ToastService) { }
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public fileOver(event){
 | 
			
		||||
    console.log(event);
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
  public fileLeave(event){
 | 
			
		||||
    console.log(event);
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
  public dropped(files: NgxFileDropEntry[]) {
 | 
			
		||||
    for (const droppedFile of files) {
 | 
			
		||||
      if (droppedFile.fileEntry.isFile) {
 | 
			
		||||
        const fileEntry = droppedFile.fileEntry as FileSystemFileEntry;
 | 
			
		||||
        console.log(fileEntry)
 | 
			
		||||
        fileEntry.file((file: File) => {
 | 
			
		||||
          console.log(file)
 | 
			
		||||
          const formData = new FormData()
 | 
			
		||||
          formData.append('document', file, file.name)
 | 
			
		||||
          this.documentService.uploadDocument(formData).subscribe(result => {
 | 
			
		||||
            this.toastService.showToast(Toast.make("Information", "The document has been uploaded and will be processed by the consumer shortly."))
 | 
			
		||||
          }, error => {
 | 
			
		||||
            this.toastService.showToast(Toast.makeError("An error has occured while uploading the document. Sorry!"))
 | 
			
		||||
          })
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
<div class="card mb-3 shadow">
 | 
			
		||||
  <div class="card-header">
 | 
			
		||||
    <h5 class="card-title mb-0">{{title}}</h5>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="card-body text-dark">
 | 
			
		||||
    <ng-content></ng-content>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -0,0 +1,25 @@
 | 
			
		||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
 | 
			
		||||
 | 
			
		||||
import { WidgetFrameComponent } from './widget-frame.component';
 | 
			
		||||
 | 
			
		||||
describe('WidgetFrameComponent', () => {
 | 
			
		||||
  let component: WidgetFrameComponent;
 | 
			
		||||
  let fixture: ComponentFixture<WidgetFrameComponent>;
 | 
			
		||||
 | 
			
		||||
  beforeEach(async () => {
 | 
			
		||||
    await TestBed.configureTestingModule({
 | 
			
		||||
      declarations: [ WidgetFrameComponent ]
 | 
			
		||||
    })
 | 
			
		||||
    .compileComponents();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  beforeEach(() => {
 | 
			
		||||
    fixture = TestBed.createComponent(WidgetFrameComponent);
 | 
			
		||||
    component = fixture.componentInstance;
 | 
			
		||||
    fixture.detectChanges();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should create', () => {
 | 
			
		||||
    expect(component).toBeTruthy();
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,18 @@
 | 
			
		||||
import { Component, Input, OnInit } from '@angular/core';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-widget-frame',
 | 
			
		||||
  templateUrl: './widget-frame.component.html',
 | 
			
		||||
  styleUrls: ['./widget-frame.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class WidgetFrameComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
  constructor() { }
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  title: string
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -3,19 +3,19 @@
 | 
			
		||||
        <svg class="buttonicon" fill="currentColor">
 | 
			
		||||
            <use xlink:href="assets/bootstrap-icons.svg#trash" />
 | 
			
		||||
        </svg>
 | 
			
		||||
        <span class="d-none d-lg-inline">Delete</span>
 | 
			
		||||
        <span class="d-none d-lg-inline"> Delete</span>
 | 
			
		||||
    </button>
 | 
			
		||||
    <a [href]="downloadUrl" class="btn btn-sm btn-outline-secondary mr-2">
 | 
			
		||||
    <a [href]="downloadUrl" class="btn btn-sm btn-outline-primary mr-2">
 | 
			
		||||
        <svg class="buttonicon" fill="currentColor">
 | 
			
		||||
            <use xlink:href="assets/bootstrap-icons.svg#download" />
 | 
			
		||||
        </svg>
 | 
			
		||||
        <span class="d-none d-lg-inline">Download</span>
 | 
			
		||||
        <span class="d-none d-lg-inline"> Download</span>
 | 
			
		||||
    </a>
 | 
			
		||||
    <button type="button" class="btn btn-sm btn-outline-secondary" (click)="close()">
 | 
			
		||||
    <button type="button" class="btn btn-sm btn-outline-primary" (click)="close()">
 | 
			
		||||
        <svg class="buttonicon" fill="currentColor">
 | 
			
		||||
            <use xlink:href="assets/bootstrap-icons.svg#x" />
 | 
			
		||||
        </svg>
 | 
			
		||||
        <span class="d-none d-lg-inline">Close</span>
 | 
			
		||||
        <span class="d-none d-lg-inline"> Close</span>
 | 
			
		||||
    </button>
 | 
			
		||||
</app-page-header>
 | 
			
		||||
 | 
			
		||||
@@ -23,17 +23,17 @@
 | 
			
		||||
<div class="row">
 | 
			
		||||
    <div class="col-xl">
 | 
			
		||||
        <form [formGroup]='documentForm' (ngSubmit)="save()">
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            <app-input-text title="Title" formControlName="title"></app-input-text>
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            <div class="form-group">
 | 
			
		||||
                <label for="archive_serial_number">Archive Serial Number</label>
 | 
			
		||||
                <input type="number" class="form-control" id="archive_serial_number"
 | 
			
		||||
                    formControlName='archive_serial_number'>
 | 
			
		||||
            </div>
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            <app-input-date-time title="Date created" titleTime="Time created" formControlName="created"></app-input-date-time>
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            <div class="form-group">
 | 
			
		||||
                <label for="content">Content</label>
 | 
			
		||||
                <textarea class="form-control" id="content" rows="5" formControlName='content'></textarea>
 | 
			
		||||
@@ -58,4 +58,4 @@
 | 
			
		||||
        </object>
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@ import { TagEditDialogComponent } from '../manage/tag-list/tag-edit-dialog/tag-e
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-document-detail',
 | 
			
		||||
  templateUrl: './document-detail.component.html',
 | 
			
		||||
  styleUrls: ['./document-detail.component.css']
 | 
			
		||||
  styleUrls: ['./document-detail.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class DocumentDetailComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<div class="card mb-3 bg-light">
 | 
			
		||||
<div class="card mb-3 bg-light shadow-sm">
 | 
			
		||||
  <div class="row no-gutters">
 | 
			
		||||
    <div class="col-md-2 d-none d-lg-block">
 | 
			
		||||
      <img [src]="getThumbUrl()" class="card-img doc-img">
 | 
			
		||||
      <img [src]="getThumbUrl()" class="card-img doc-img border-right">
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="col">
 | 
			
		||||
      <div class="card-body">
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ import { DocumentService } from 'src/app/services/rest/document.service';
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-document-card-large',
 | 
			
		||||
  templateUrl: './document-card-large.component.html',
 | 
			
		||||
  styleUrls: ['./document-card-large.component.css']
 | 
			
		||||
  styleUrls: ['./document-card-large.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class DocumentCardLargeComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +0,0 @@
 | 
			
		||||
.doc-img {
 | 
			
		||||
  object-fit: cover;
 | 
			
		||||
  object-position: top;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,11 +1,20 @@
 | 
			
		||||
<div class="col-auto mb-3">
 | 
			
		||||
  <div class="card h-100 bg-light" style="width: 14rem">
 | 
			
		||||
    <div style="height: 10rem; overflow: hidden;">
 | 
			
		||||
      <img [src]="getThumbUrl()" class="card-img doc-img"/>
 | 
			
		||||
<div class="col p-2 h-100" style="width: 16rem;">
 | 
			
		||||
  <div class="card h-100 shadow-sm">
 | 
			
		||||
    <div class=" border-bottom doc-img pr-1" [ngStyle]="{'background-image': 'url(' + getThumbUrl() + ')'}">
 | 
			
		||||
      <div class="row" *ngFor="let t of document.tags">
 | 
			
		||||
        <app-tag [tag]="t" class="col text-right"></app-tag>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="card-body">
 | 
			
		||||
      <p class="card-title">{{document.correspondent ? document.correspondent.name + ': ' : ''}}{{document.title}} <app-tag [tag]="t" *ngFor="let t of document.tags" class="ml-1"></app-tag></p>
 | 
			
		||||
      <div class="d-flex justify-content-between align-items-center">
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <div class="card-body p-2">
 | 
			
		||||
      <p class="card-text">
 | 
			
		||||
        <span class="font-weight-bold">{{document.correspondent? document.correspondent.name + ': ' : ''}}</span> {{document.title}}
 | 
			
		||||
      </p>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="card-footer">
 | 
			
		||||
 | 
			
		||||
      <div class="d-flex justify-content-between align-items-center ml-n2">
 | 
			
		||||
        <div class="btn-group">
 | 
			
		||||
          <a routerLink="/documents/{{document.id}}" class="btn btn-sm btn-outline-secondary">
 | 
			
		||||
            <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-pencil" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
 | 
			
		||||
@@ -21,6 +30,7 @@
 | 
			
		||||
        </div>
 | 
			
		||||
        <small class="text-muted">{{document.created | date}}</small>
 | 
			
		||||
      </div>
 | 
			
		||||
      
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
  </div>  
 | 
			
		||||
</div>
 | 
			
		||||
@@ -0,0 +1,5 @@
 | 
			
		||||
.doc-img {
 | 
			
		||||
  background-size: cover;
 | 
			
		||||
  background-position: top;
 | 
			
		||||
  height: 200px;
 | 
			
		||||
}
 | 
			
		||||
@@ -5,7 +5,7 @@ import { DocumentService } from 'src/app/services/rest/document.service';
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-document-card-small',
 | 
			
		||||
  templateUrl: './document-card-small.component.html',
 | 
			
		||||
  styleUrls: ['./document-card-small.component.css']
 | 
			
		||||
  styleUrls: ['./document-card-small.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class DocumentCardSmallComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,51 +1,51 @@
 | 
			
		||||
<app-page-header [title]="getTitle()">
 | 
			
		||||
 | 
			
		||||
  <div class="btn-group btn-group-toggle mr-2" ngbRadioGroup [(ngModel)]="displayMode"
 | 
			
		||||
  <div class="btn-group btn-group-toggle" ngbRadioGroup [(ngModel)]="displayMode"
 | 
			
		||||
    (ngModelChange)="saveDisplayMode()">
 | 
			
		||||
    <label ngbButtonLabel class="btn-outline-secondary btn-sm">
 | 
			
		||||
    <label ngbButtonLabel class="btn-outline-primary btn-sm">
 | 
			
		||||
      <input ngbButton type="radio" class="btn btn-sm" value="details">
 | 
			
		||||
      <svg class="toolbaricon" fill="currentColor">
 | 
			
		||||
        <use xlink:href="assets/bootstrap-icons.svg#list-ul" />
 | 
			
		||||
      </svg>
 | 
			
		||||
    </label>
 | 
			
		||||
    <label ngbButtonLabel class="btn-outline-secondary btn-sm">
 | 
			
		||||
    <label ngbButtonLabel class="btn-outline-primary btn-sm">
 | 
			
		||||
      <input ngbButton type="radio" class="btn btn-sm" value="smallCards">
 | 
			
		||||
      <svg class="toolbaricon" fill="currentColor">
 | 
			
		||||
        <use xlink:href="assets/bootstrap-icons.svg#grid" />
 | 
			
		||||
      </svg>
 | 
			
		||||
    </label>
 | 
			
		||||
    <label ngbButtonLabel class="btn-outline-secondary btn-sm">
 | 
			
		||||
    <label ngbButtonLabel class="btn-outline-primary btn-sm">
 | 
			
		||||
      <input ngbButton type="radio" class="btn btn-sm" value="largeCards">
 | 
			
		||||
      <svg class="toolbaricon" fill="currentColor">
 | 
			
		||||
        <use xlink:href="assets/bootstrap-icons.svg#hdd-stack" />
 | 
			
		||||
      </svg>
 | 
			
		||||
    </label>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="btn-group btn-group-toggle mr-2" ngbRadioGroup [(ngModel)]="docs.sortDirection"
 | 
			
		||||
  <div class="btn-group btn-group-toggle ml-2" ngbRadioGroup [(ngModel)]="docs.sortDirection"
 | 
			
		||||
    *ngIf="!docs.viewId">
 | 
			
		||||
    <div ngbDropdown class="btn-group">
 | 
			
		||||
      <button class="btn btn-outline-secondary btn-sm" id="dropdownBasic1" ngbDropdownToggle>Sort by</button>
 | 
			
		||||
      <button class="btn btn-outline-primary btn-sm" id="dropdownBasic1" ngbDropdownToggle>Sort by</button>
 | 
			
		||||
      <div ngbDropdownMenu aria-labelledby="dropdownBasic1">
 | 
			
		||||
        <button *ngFor="let f of getSortFields()" ngbDropdownItem (click)="setSort(f.field)"
 | 
			
		||||
          [class.active]="docs.sortField == f.field">{{f.name}}</button>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <label ngbButtonLabel class="btn-outline-secondary btn-sm">
 | 
			
		||||
    <label ngbButtonLabel class="btn-outline-primary btn-sm">
 | 
			
		||||
      <input ngbButton type="radio" class="btn btn-sm" value="asc">
 | 
			
		||||
      <svg class="toolbaricon" fill="currentColor">
 | 
			
		||||
        <use xlink:href="assets/bootstrap-icons.svg#sort-alpha-down" />
 | 
			
		||||
      </svg>
 | 
			
		||||
    </label>
 | 
			
		||||
    <label ngbButtonLabel class="btn-outline-secondary btn-sm">
 | 
			
		||||
    <label ngbButtonLabel class="btn-outline-primary btn-sm">
 | 
			
		||||
      <input ngbButton type="radio" class="btn btn-sm" value="des">
 | 
			
		||||
      <svg class="toolbaricon" fill="currentColor">
 | 
			
		||||
        <use xlink:href="assets/bootstrap-icons.svg#sort-alpha-up-alt" />
 | 
			
		||||
      </svg>
 | 
			
		||||
    </label>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="btn-group" *ngIf="!docs.viewId">
 | 
			
		||||
  <div class="btn-group ml-2" *ngIf="!docs.viewId">
 | 
			
		||||
 | 
			
		||||
    <button type="button" class="btn btn-sm btn-outline-secondary" (click)="showFilter=!showFilter">
 | 
			
		||||
    <button type="button" class="btn btn-sm btn-outline-primary" (click)="showFilter=!showFilter">
 | 
			
		||||
      <svg class="toolbaricon" fill="currentColor">
 | 
			
		||||
        <use xlink:href="assets/bootstrap-icons.svg#funnel" />
 | 
			
		||||
      </svg>
 | 
			
		||||
@@ -53,7 +53,7 @@
 | 
			
		||||
    </button>
 | 
			
		||||
 | 
			
		||||
    <div class="btn-group" ngbDropdown role="group">
 | 
			
		||||
      <button class="btn btn-sm btn-outline-secondary dropdown-toggle-split" ngbDropdownToggle></button>
 | 
			
		||||
      <button class="btn btn-sm btn-outline-primary dropdown-toggle-split" ngbDropdownToggle></button>
 | 
			
		||||
      <div class="dropdown-menu" ngbDropdownMenu>
 | 
			
		||||
        <button ngbDropdownItem *ngFor="let config of savedViewConfigService.getConfigs()" (click)="loadViewConfig(config)">{{config.title}}</button>
 | 
			
		||||
        <div class="dropdown-divider" *ngIf="savedViewConfigService.getConfigs().length > 0"></div>
 | 
			
		||||
@@ -71,38 +71,40 @@
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<ngb-pagination [pageSize]="docs.currentPageSize" [collectionSize]="docs.collectionSize" [(page)]="docs.currentPage" [maxSize]="5"
 | 
			
		||||
  [rotate]="true" [boundaryLinks]="true" (pageChange)="reload()" aria-label="Default pagination"></ngb-pagination>
 | 
			
		||||
<div class="row m-0 justify-content-end">
 | 
			
		||||
  <ngb-pagination [pageSize]="docs.currentPageSize" [collectionSize]="docs.collectionSize" [(page)]="docs.currentPage" [maxSize]="5"
 | 
			
		||||
  [rotate]="true" (pageChange)="reload()" aria-label="Default pagination"></ngb-pagination>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<div *ngIf="displayMode == 'largeCards'">
 | 
			
		||||
  <app-document-card-large *ngFor="let d of docs.documents" [document]="d" [details]="d.content">
 | 
			
		||||
  </app-document-card-large>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<table class="table table-hover table-sm" *ngIf="displayMode == 'details'">
 | 
			
		||||
<table class="table table-hover table-sm border shadow" *ngIf="displayMode == 'details'">
 | 
			
		||||
  <thead>
 | 
			
		||||
    <th>ASN</th>
 | 
			
		||||
    <th>Correspondent</th>
 | 
			
		||||
    <th class="d-none d-lg-table-cell">ASN</th>
 | 
			
		||||
    <th class="d-none d-md-table-cell">Correspondent</th>
 | 
			
		||||
    <th>Title</th>
 | 
			
		||||
    <th>Document type</th>
 | 
			
		||||
    <th class="d-none d-xl-table-cell">Document type</th>
 | 
			
		||||
    <th>Created</th>
 | 
			
		||||
    <th>Added</th>
 | 
			
		||||
    <th class="d-none d-xl-table-cell">Added</th>
 | 
			
		||||
  </thead>
 | 
			
		||||
  <tbody>
 | 
			
		||||
    <tr *ngFor="let d of docs.documents" routerLink="/documents/{{d.id}}">
 | 
			
		||||
      <td>{{d.archive_serial_number}}</td>
 | 
			
		||||
      <td>{{d.correspondent ? d.correspondent.name : ''}}</td>
 | 
			
		||||
      <td>{{d.title}}<app-tag [tag]="t" *ngFor="let t of d.tags" class="ml-1"></app-tag>
 | 
			
		||||
      </td>
 | 
			
		||||
      <td>{{d.document_type ? d.document_type.name : ''}}</td>
 | 
			
		||||
      <td class="d-none d-lg-table-cell">{{d.archive_serial_number}}</td>
 | 
			
		||||
      <td class="d-none d-md-table-cell">{{d.correspondent ? d.correspondent.name : ''}}</td>
 | 
			
		||||
      <td>{{d.title}}<app-tag [tag]="t" *ngFor="let t of d.tags" class="ml-1"></app-tag></td>
 | 
			
		||||
      <td class="d-none d-xl-table-cell">{{d.document_type ? d.document_type.name : ''}}</td>
 | 
			
		||||
      <td>{{d.created | date}}</td>
 | 
			
		||||
      <td>{{d.added | date}}</td>
 | 
			
		||||
      <td class="d-none d-xl-table-cell">{{d.added | date}}</td>
 | 
			
		||||
    </tr>
 | 
			
		||||
  </tbody>
 | 
			
		||||
</table>
 | 
			
		||||
 | 
			
		||||
<div class="row justify-content-left" *ngIf="displayMode == 'smallCards'">
 | 
			
		||||
  <app-document-card-small [document]="d" *ngFor="let d of docs.documents"></app-document-card-small>
 | 
			
		||||
 | 
			
		||||
<div class=" m-n2 row" *ngIf="displayMode == 'smallCards'">
 | 
			
		||||
  <app-document-card-small [document]="d" *ngFor="let d of docs.documents"></app-document-card-small>    
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<p *ngIf="docs.documents.length == 0" class="mx-auto">No results</p>
 | 
			
		||||
@@ -11,7 +11,7 @@ import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-vi
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-document-list',
 | 
			
		||||
  templateUrl: './document-list.component.html',
 | 
			
		||||
  styleUrls: ['./document-list.component.css']
 | 
			
		||||
  styleUrls: ['./document-list.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class DocumentListComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@ import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-save-view-config-dialog',
 | 
			
		||||
  templateUrl: './save-view-config-dialog.component.html',
 | 
			
		||||
  styleUrls: ['./save-view-config-dialog.component.css']
 | 
			
		||||
  styleUrls: ['./save-view-config-dialog.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class SaveViewConfigDialogComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ import { TagService } from 'src/app/services/rest/tag.service';
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-filter-editor',
 | 
			
		||||
  templateUrl: './filter-editor.component.html',
 | 
			
		||||
  styleUrls: ['./filter-editor.component.css']
 | 
			
		||||
  styleUrls: ['./filter-editor.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class FilterEditorComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@ import { ToastService } from 'src/app/services/toast.service';
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-correspondent-edit-dialog',
 | 
			
		||||
  templateUrl: './correspondent-edit-dialog.component.html',
 | 
			
		||||
  styleUrls: ['./correspondent-edit-dialog.component.css']
 | 
			
		||||
  styleUrls: ['./correspondent-edit-dialog.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class CorrespondentEditDialogComponent extends EditDialogComponent<PaperlessCorrespondent> {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,14 @@
 | 
			
		||||
<app-page-header title="Correspondents">
 | 
			
		||||
  <button type="button" class="btn btn-sm btn-outline-secondary" (click)="openCreateDialog()">
 | 
			
		||||
  <button type="button" class="btn btn-sm btn-outline-primary" (click)="openCreateDialog()">
 | 
			
		||||
    Create
 | 
			
		||||
  </button>
 | 
			
		||||
</app-page-header>
 | 
			
		||||
 | 
			
		||||
<ngb-pagination [pageSize]="25" [collectionSize]="collectionSize" [(page)]="page" (pageChange)="reloadData()" aria-label="Default pagination"></ngb-pagination>
 | 
			
		||||
<div class="row m-0 justify-content-end">
 | 
			
		||||
  <ngb-pagination [pageSize]="25" [collectionSize]="collectionSize" [(page)]="page" (pageChange)="reloadData()" aria-label="Default pagination"></ngb-pagination>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<table class="table table-striped">
 | 
			
		||||
<table class="table table-striped border shadow">
 | 
			
		||||
    <thead>
 | 
			
		||||
    <tr>
 | 
			
		||||
      <th scope="col" sortable="name" (sort)="onSort($event)">Name</th>
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ import { CorrespondentEditDialogComponent } from './correspondent-edit-dialog/co
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-correspondent-list',
 | 
			
		||||
  templateUrl: './correspondent-list.component.html',
 | 
			
		||||
  styleUrls: ['./correspondent-list.component.css']
 | 
			
		||||
  styleUrls: ['./correspondent-list.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class CorrespondentListComponent extends GenericListComponent<PaperlessCorrespondent> {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@ import { ToastService } from 'src/app/services/toast.service';
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-document-type-edit-dialog',
 | 
			
		||||
  templateUrl: './document-type-edit-dialog.component.html',
 | 
			
		||||
  styleUrls: ['./document-type-edit-dialog.component.css']
 | 
			
		||||
  styleUrls: ['./document-type-edit-dialog.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class DocumentTypeEditDialogComponent extends EditDialogComponent<PaperlessDocumentType> {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,15 @@
 | 
			
		||||
<app-page-header title="Document types">
 | 
			
		||||
  <button type="button" class="btn btn-sm btn-outline-secondary" (click)="openCreateDialog()">
 | 
			
		||||
  <button type="button" class="btn btn-sm btn-outline-primary" (click)="openCreateDialog()">
 | 
			
		||||
    Create
 | 
			
		||||
  </button>
 | 
			
		||||
</app-page-header>
 | 
			
		||||
 | 
			
		||||
<ngb-pagination [pageSize]="25" [collectionSize]="collectionSize" [(page)]="page" (pageChange)="reloadData()"
 | 
			
		||||
<div class="row m-0 justify-content-end">
 | 
			
		||||
  <ngb-pagination [pageSize]="25" [collectionSize]="collectionSize" [(page)]="page" (pageChange)="reloadData()"
 | 
			
		||||
  aria-label="Default pagination"></ngb-pagination>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<table class="table table-striped">
 | 
			
		||||
<table class="table table-striped border shadow">
 | 
			
		||||
  <thead>
 | 
			
		||||
    <tr>
 | 
			
		||||
      <th scope="col" sortable="name" (sort)="onSort($event)">Name</th>
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ import { DocumentTypeEditDialogComponent } from './document-type-edit-dialog/doc
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-document-type-list',
 | 
			
		||||
  templateUrl: './document-type-list.component.html',
 | 
			
		||||
  styleUrls: ['./document-type-list.component.css']
 | 
			
		||||
  styleUrls: ['./document-type-list.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class DocumentTypeListComponent extends GenericListComponent<PaperlessDocumentType> {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<app-page-header title="Logs">
 | 
			
		||||
 | 
			
		||||
  <div ngbDropdown class="btn-group">
 | 
			
		||||
    <button class="btn btn-outline-secondary btn-sm" id="dropdownBasic1" ngbDropdownToggle>
 | 
			
		||||
    <button class="btn btn-outline-primary btn-sm" id="dropdownBasic1" ngbDropdownToggle>
 | 
			
		||||
      <svg class="toolbaricon" fill="currentColor">
 | 
			
		||||
        <use xlink:href="assets/bootstrap-icons.svg#funnel" />
 | 
			
		||||
      </svg>
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ import { LogService } from 'src/app/services/rest/log.service';
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-logs',
 | 
			
		||||
  templateUrl: './logs.component.html',
 | 
			
		||||
  styleUrls: ['./logs.component.css']
 | 
			
		||||
  styleUrls: ['./logs.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class LogsComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -57,7 +57,7 @@
 | 
			
		||||
    </li>
 | 
			
		||||
  </ul>
 | 
			
		||||
 | 
			
		||||
  <div [ngbNavOutlet]="nav" class="border-left border-right border-bottom p-3 mb-3"></div>
 | 
			
		||||
  <div [ngbNavOutlet]="nav" class="border-left border-right border-bottom p-3 mb-3 shadow"></div>
 | 
			
		||||
 | 
			
		||||
  <button type="submit" class="btn btn-primary">Save</button>
 | 
			
		||||
</form>
 | 
			
		||||
@@ -8,7 +8,7 @@ import { SavedViewConfigService } from 'src/app/services/saved-view-config.servi
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-settings',
 | 
			
		||||
  templateUrl: './settings.component.html',
 | 
			
		||||
  styleUrls: ['./settings.component.css']
 | 
			
		||||
  styleUrls: ['./settings.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class SettingsComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@ import { ToastService } from 'src/app/services/toast.service';
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-tag-edit-dialog',
 | 
			
		||||
  templateUrl: './tag-edit-dialog.component.html',
 | 
			
		||||
  styleUrls: ['./tag-edit-dialog.component.css']
 | 
			
		||||
  styleUrls: ['./tag-edit-dialog.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class TagEditDialogComponent extends EditDialogComponent<PaperlessTag> {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,34 +1,37 @@
 | 
			
		||||
<app-page-header title="Tags">
 | 
			
		||||
  <button type="button" class="btn btn-sm btn-outline-secondary" (click)="openCreateDialog()">
 | 
			
		||||
  <button type="button" class="btn btn-sm btn-outline-primary" (click)="openCreateDialog()">
 | 
			
		||||
    Create
 | 
			
		||||
  </button>
 | 
			
		||||
</app-page-header>
 | 
			
		||||
  
 | 
			
		||||
<ngb-pagination [pageSize]="25" [collectionSize]="collectionSize" [(page)]="page" (pageChange)="reloadData()" aria-label="Default pagination"></ngb-pagination>
 | 
			
		||||
  
 | 
			
		||||
  <table class="table table-striped">
 | 
			
		||||
      <thead>
 | 
			
		||||
      <tr>
 | 
			
		||||
        <th scope="col" sortable="name" (sort)="onSort($event)">Name</th>
 | 
			
		||||
        <th scope="col">Colour</th>
 | 
			
		||||
        <th scope="col" sortable="matching_algorithm" (sort)="onSort($event)">Matching</th>
 | 
			
		||||
        <th scope="col" sortable="document_count" (sort)="onSort($event)">Document count</th>
 | 
			
		||||
        <th scope="col">Actions</th>
 | 
			
		||||
      </tr>
 | 
			
		||||
      </thead>
 | 
			
		||||
      <tbody>
 | 
			
		||||
      <tr *ngFor="let tag of data">
 | 
			
		||||
          <td scope="row">{{ tag.name }}</td>
 | 
			
		||||
          <td scope="row"><span class="badge" [style.color]="getColor(tag.colour).textColor" [style.background-color]="getColor(tag.colour).value">{{ getColor(tag.colour).name }}</span></td>
 | 
			
		||||
          <td scope="row">{{ getMatching(tag) }}</td>
 | 
			
		||||
          <td scope="row">{{ tag.document_count }}</td>
 | 
			
		||||
          <td scope="row">
 | 
			
		||||
            <div class="btn-group">
 | 
			
		||||
            <button class="btn btn-sm btn-outline-secondary" (click)="openEditDialog(tag)">Edit</button>
 | 
			
		||||
            <button class="btn btn-sm btn-outline-danger" (click)="openDeleteDialog(tag)">Delete</button>
 | 
			
		||||
          </div>
 | 
			
		||||
          </td>
 | 
			
		||||
      </tr>
 | 
			
		||||
      </tbody>
 | 
			
		||||
    </table>
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
<div class="row m-0 justify-content-end">
 | 
			
		||||
  <ngb-pagination [pageSize]="25" [collectionSize]="collectionSize" [(page)]="page" (pageChange)="reloadData()"
 | 
			
		||||
    aria-label="Default pagination"></ngb-pagination>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<table class="table table-striped border shadow">
 | 
			
		||||
  <thead>
 | 
			
		||||
    <tr>
 | 
			
		||||
      <th scope="col" sortable="name" (sort)="onSort($event)">Name</th>
 | 
			
		||||
      <th scope="col">Colour</th>
 | 
			
		||||
      <th scope="col" sortable="matching_algorithm" (sort)="onSort($event)">Matching</th>
 | 
			
		||||
      <th scope="col" sortable="document_count" (sort)="onSort($event)">Document count</th>
 | 
			
		||||
      <th scope="col">Actions</th>
 | 
			
		||||
    </tr>
 | 
			
		||||
  </thead>
 | 
			
		||||
  <tbody>
 | 
			
		||||
    <tr *ngFor="let tag of data">
 | 
			
		||||
      <td scope="row">{{ tag.name }}</td>
 | 
			
		||||
      <td scope="row"><span class="badge" [style.color]="getColor(tag.colour).textColor"
 | 
			
		||||
          [style.background-color]="getColor(tag.colour).value">{{ getColor(tag.colour).name }}</span></td>
 | 
			
		||||
      <td scope="row">{{ getMatching(tag) }}</td>
 | 
			
		||||
      <td scope="row">{{ tag.document_count }}</td>
 | 
			
		||||
      <td scope="row">
 | 
			
		||||
        <div class="btn-group">
 | 
			
		||||
          <button class="btn btn-sm btn-outline-secondary" (click)="openEditDialog(tag)">Edit</button>
 | 
			
		||||
          <button class="btn btn-sm btn-outline-danger" (click)="openDeleteDialog(tag)">Delete</button>
 | 
			
		||||
        </div>
 | 
			
		||||
      </td>
 | 
			
		||||
    </tr>
 | 
			
		||||
  </tbody>
 | 
			
		||||
</table>
 | 
			
		||||
@@ -9,7 +9,7 @@ import { TagEditDialogComponent } from './tag-edit-dialog/tag-edit-dialog.compon
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-tag-list',
 | 
			
		||||
  templateUrl: './tag-list.component.html',
 | 
			
		||||
  styleUrls: ['./tag-list.component.css']
 | 
			
		||||
  styleUrls: ['./tag-list.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class TagListComponent extends GenericListComponent<PaperlessTag> {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ import { Component, OnInit } from '@angular/core';
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-not-found',
 | 
			
		||||
  templateUrl: './not-found.component.html',
 | 
			
		||||
  styleUrls: ['./not-found.component.css']
 | 
			
		||||
  styleUrls: ['./not-found.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class NotFoundComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ import { SearchHitHighlight } from 'src/app/data/search-result';
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-result-hightlight',
 | 
			
		||||
  templateUrl: './result-hightlight.component.html',
 | 
			
		||||
  styleUrls: ['./result-hightlight.component.css']
 | 
			
		||||
  styleUrls: ['./result-hightlight.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class ResultHightlightComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user